LCOV - code coverage report
Current view: top level - extensions/auth - nsHttpNegotiateAuth.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 203 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 25 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* vim:set ts=4 sw=4 sts=4 et cindent: */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : //
       7             : // HTTP Negotiate Authentication Support Module
       8             : //
       9             : // Described by IETF Internet draft: draft-brezak-kerberos-http-00.txt
      10             : // (formerly draft-brezak-spnego-http-04.txt)
      11             : //
      12             : // Also described here:
      13             : // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/http-sso-1.asp
      14             : //
      15             : 
      16             : #include <string.h>
      17             : #include <stdlib.h>
      18             : 
      19             : #include "nsAuth.h"
      20             : #include "nsHttpNegotiateAuth.h"
      21             : 
      22             : #include "nsIHttpAuthenticableChannel.h"
      23             : #include "nsIProxiedChannel.h"
      24             : #include "nsIAuthModule.h"
      25             : #include "nsIServiceManager.h"
      26             : #include "nsIPrefService.h"
      27             : #include "nsIPrefBranch.h"
      28             : #include "nsIProxyInfo.h"
      29             : #include "nsIURI.h"
      30             : #include "nsCOMPtr.h"
      31             : #include "nsString.h"
      32             : #include "nsNetCID.h"
      33             : #include "plbase64.h"
      34             : #include "plstr.h"
      35             : #include "mozilla/Base64.h"
      36             : #include "mozilla/Logging.h"
      37             : #include "mozilla/Tokenizer.h"
      38             : #include "mozilla/UniquePtr.h"
      39             : #include "mozilla/Unused.h"
      40             : #include "prmem.h"
      41             : #include "prnetdb.h"
      42             : #include "mozilla/Likely.h"
      43             : #include "mozilla/Sprintf.h"
      44             : #include "nsIChannel.h"
      45             : #include "nsNetUtil.h"
      46             : #include "nsThreadUtils.h"
      47             : #include "nsIHttpAuthenticatorCallback.h"
      48             : #include "mozilla/Mutex.h"
      49             : #include "nsICancelable.h"
      50             : #include "nsUnicharUtils.h"
      51             : #include "mozilla/net/HttpAuthUtils.h"
      52             : 
      53             : using mozilla::Base64Decode;
      54             : 
      55             : //-----------------------------------------------------------------------------
      56             : 
      57             : static const char kNegotiate[] = "Negotiate";
      58             : static const char kNegotiateAuthTrustedURIs[] = "network.negotiate-auth.trusted-uris";
      59             : static const char kNegotiateAuthDelegationURIs[] = "network.negotiate-auth.delegation-uris";
      60             : static const char kNegotiateAuthAllowProxies[] = "network.negotiate-auth.allow-proxies";
      61             : static const char kNegotiateAuthAllowNonFqdn[] = "network.negotiate-auth.allow-non-fqdn";
      62             : static const char kNegotiateAuthSSPI[] = "network.auth.use-sspi";
      63             : static const char kSSOinPBmode[] = "network.auth.private-browsing-sso";
      64             : 
      65             : #define kNegotiateLen  (sizeof(kNegotiate)-1)
      66             : #define DEFAULT_THREAD_TIMEOUT_MS 30000
      67             : 
      68             : //-----------------------------------------------------------------------------
      69             : 
      70             : // Return false when the channel comes from a Private browsing window.
      71             : static bool
      72           0 : TestNotInPBMode(nsIHttpAuthenticableChannel *authChannel, bool proxyAuth)
      73             : {
      74             :     // Proxy should go all the time, it's not considered a privacy leak
      75             :     // to send default credentials to a proxy.
      76           0 :     if (proxyAuth) {
      77           0 :         return true;
      78             :     }
      79             : 
      80           0 :     nsCOMPtr<nsIChannel> bareChannel = do_QueryInterface(authChannel);
      81           0 :     MOZ_ASSERT(bareChannel);
      82             : 
      83           0 :     if (!NS_UsePrivateBrowsing(bareChannel)) {
      84           0 :         return true;
      85             :     }
      86             : 
      87           0 :     nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
      88           0 :     if (prefs) {
      89             :         bool ssoInPb;
      90           0 :         if (NS_SUCCEEDED(prefs->GetBoolPref(kSSOinPBmode, &ssoInPb)) && ssoInPb) {
      91           0 :             return true;
      92             :         }
      93             : 
      94             :         // When the "Never remember history" option is set, all channels are
      95             :         // set PB mode flag, but here we want to make an exception, users
      96             :         // want their credentials go out.
      97             :         bool dontRememberHistory;
      98           0 :         if (NS_SUCCEEDED(prefs->GetBoolPref("browser.privatebrowsing.autostart",
      99           0 :                                             &dontRememberHistory)) &&
     100             :             dontRememberHistory) {
     101           0 :             return true;
     102             :         }
     103             :     }
     104             : 
     105           0 :     return false;
     106             : }
     107             : 
     108             : NS_IMETHODIMP
     109           0 : nsHttpNegotiateAuth::GetAuthFlags(uint32_t *flags)
     110             : {
     111             :     //
     112             :     // Negotiate Auth creds should not be reused across multiple requests.
     113             :     // Only perform the negotiation when it is explicitly requested by the
     114             :     // server.  Thus, do *NOT* use the "REUSABLE_CREDENTIALS" flag here.
     115             :     //
     116             :     // CONNECTION_BASED is specified instead of REQUEST_BASED since we need
     117             :     // to complete a sequence of transactions with the server over the same
     118             :     // connection.
     119             :     //
     120           0 :     *flags = CONNECTION_BASED | IDENTITY_IGNORED;
     121           0 :     return NS_OK;
     122             : }
     123             : 
     124             : //
     125             : // Always set *identityInvalid == FALSE here.  This
     126             : // will prevent the browser from popping up the authentication
     127             : // prompt window.  Because GSSAPI does not have an API
     128             : // for fetching initial credentials (ex: A Kerberos TGT),
     129             : // there is no correct way to get the users credentials.
     130             : //
     131             : NS_IMETHODIMP
     132           0 : nsHttpNegotiateAuth::ChallengeReceived(nsIHttpAuthenticableChannel *authChannel,
     133             :                                        const char *challenge,
     134             :                                        bool isProxyAuth,
     135             :                                        nsISupports **sessionState,
     136             :                                        nsISupports **continuationState,
     137             :                                        bool *identityInvalid)
     138             : {
     139           0 :     nsIAuthModule *module = (nsIAuthModule *) *continuationState;
     140             : 
     141           0 :     *identityInvalid = false;
     142           0 :     if (module)
     143           0 :         return NS_OK;
     144             : 
     145             :     nsresult rv;
     146             : 
     147           0 :     nsCOMPtr<nsIURI> uri;
     148           0 :     rv = authChannel->GetURI(getter_AddRefs(uri));
     149           0 :     if (NS_FAILED(rv))
     150           0 :         return rv;
     151             : 
     152           0 :     uint32_t req_flags = nsIAuthModule::REQ_DEFAULT;
     153           0 :     nsAutoCString service;
     154             : 
     155           0 :     if (isProxyAuth) {
     156           0 :         if (!TestBoolPref(kNegotiateAuthAllowProxies)) {
     157           0 :             LOG(("nsHttpNegotiateAuth::ChallengeReceived proxy auth blocked\n"));
     158           0 :             return NS_ERROR_ABORT;
     159             :         }
     160             : 
     161           0 :         req_flags |= nsIAuthModule::REQ_PROXY_AUTH;
     162           0 :         nsCOMPtr<nsIProxyInfo> proxyInfo;
     163           0 :         authChannel->GetProxyInfo(getter_AddRefs(proxyInfo));
     164           0 :         NS_ENSURE_STATE(proxyInfo);
     165             : 
     166           0 :         proxyInfo->GetHost(service);
     167             :     }
     168             :     else {
     169           0 :         bool allowed = TestNotInPBMode(authChannel, isProxyAuth) &&
     170           0 :                        (TestNonFqdn(uri) ||
     171           0 :                        mozilla::net::auth::URIMatchesPrefPattern(uri, kNegotiateAuthTrustedURIs));
     172           0 :         if (!allowed) {
     173           0 :             LOG(("nsHttpNegotiateAuth::ChallengeReceived URI blocked\n"));
     174           0 :             return NS_ERROR_ABORT;
     175             :         }
     176             : 
     177           0 :         bool delegation = mozilla::net::auth::URIMatchesPrefPattern(uri, kNegotiateAuthDelegationURIs);
     178           0 :         if (delegation) {
     179           0 :             LOG(("  using REQ_DELEGATE\n"));
     180           0 :             req_flags |= nsIAuthModule::REQ_DELEGATE;
     181             :         }
     182             : 
     183           0 :         rv = uri->GetAsciiHost(service);
     184           0 :         if (NS_FAILED(rv))
     185           0 :             return rv;
     186             :     }
     187             : 
     188           0 :     LOG(("  service = %s\n", service.get()));
     189             : 
     190             :     //
     191             :     // The correct service name for IIS servers is "HTTP/f.q.d.n", so
     192             :     // construct the proper service name for passing to "gss_import_name".
     193             :     //
     194             :     // TODO: Possibly make this a configurable service name for use
     195             :     // with non-standard servers that use stuff like "khttp/f.q.d.n"
     196             :     // instead.
     197             :     //
     198           0 :     service.Insert("HTTP@", 0);
     199             : 
     200             :     const char *contractID;
     201           0 :     if (TestBoolPref(kNegotiateAuthSSPI)) {
     202           0 :            LOG(("  using negotiate-sspi\n"));
     203           0 :            contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-sspi";
     204             :     }
     205             :     else {
     206           0 :            LOG(("  using negotiate-gss\n"));
     207           0 :            contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-gss";
     208             :     }
     209             : 
     210           0 :     rv = CallCreateInstance(contractID, &module);
     211             : 
     212           0 :     if (NS_FAILED(rv)) {
     213           0 :         LOG(("  Failed to load Negotiate Module \n"));
     214           0 :         return rv;
     215             :     }
     216             : 
     217           0 :     rv = module->Init(service.get(), req_flags, nullptr, nullptr, nullptr);
     218             : 
     219           0 :     if (NS_FAILED(rv)) {
     220           0 :         NS_RELEASE(module);
     221           0 :         return rv;
     222             :     }
     223             : 
     224           0 :     *continuationState = module;
     225           0 :     return NS_OK;
     226             : }
     227             : 
     228           0 : NS_IMPL_ISUPPORTS(nsHttpNegotiateAuth, nsIHttpAuthenticator)
     229             : 
     230             : namespace {
     231             : 
     232             : //
     233             : // GetNextTokenCompleteEvent
     234             : //
     235             : // This event is fired on main thread when async call of
     236             : // nsHttpNegotiateAuth::GenerateCredentials is finished. During the Run()
     237             : // method the nsIHttpAuthenticatorCallback::OnCredsAvailable is called with
     238             : // obtained credentials, flags and NS_OK when successful, otherwise
     239             : // NS_ERROR_FAILURE is returned as a result of failed operation.
     240             : //
     241             : class GetNextTokenCompleteEvent final : public nsIRunnable,
     242             :                                         public nsICancelable
     243             : {
     244           0 :     virtual ~GetNextTokenCompleteEvent()
     245           0 :     {
     246           0 :         if (mCreds) {
     247           0 :             free(mCreds);
     248             :         }
     249           0 :     };
     250             : 
     251             : public:
     252             :     NS_DECL_THREADSAFE_ISUPPORTS
     253             : 
     254           0 :     explicit GetNextTokenCompleteEvent(nsIHttpAuthenticatorCallback* aCallback)
     255           0 :         : mCallback(aCallback)
     256             :         , mCreds(nullptr)
     257           0 :         , mCancelled(false)
     258             :     {
     259           0 :     }
     260             : 
     261           0 :     NS_IMETHODIMP DispatchSuccess(char *aCreds,
     262             :                                   uint32_t aFlags,
     263             :                                   already_AddRefed<nsISupports> aSessionState,
     264             :                                   already_AddRefed<nsISupports> aContinuationState)
     265             :     {
     266             :         // Called from worker thread
     267           0 :         MOZ_ASSERT(!NS_IsMainThread());
     268             : 
     269           0 :         mCreds = aCreds;
     270           0 :         mFlags = aFlags;
     271           0 :         mResult = NS_OK;
     272           0 :         mSessionState = aSessionState;
     273           0 :         mContinuationState = aContinuationState;
     274           0 :         return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
     275             :     }
     276             : 
     277           0 :     NS_IMETHODIMP DispatchError(already_AddRefed<nsISupports> aSessionState,
     278             :                                 already_AddRefed<nsISupports> aContinuationState)
     279             :     {
     280             :         // Called from worker thread
     281           0 :         MOZ_ASSERT(!NS_IsMainThread());
     282             : 
     283           0 :         mResult = NS_ERROR_FAILURE;
     284           0 :         mSessionState = aSessionState;
     285           0 :         mContinuationState = aContinuationState;
     286           0 :         return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
     287             :     }
     288             : 
     289           0 :     NS_IMETHODIMP Run() override
     290             :     {
     291             :         // Runs on main thread
     292           0 :         MOZ_ASSERT(NS_IsMainThread());
     293             : 
     294           0 :         if (!mCancelled) {
     295           0 :             nsCOMPtr<nsIHttpAuthenticatorCallback> callback;
     296           0 :             callback.swap(mCallback);
     297           0 :             callback->OnCredsGenerated(mCreds, mFlags, mResult, mSessionState, mContinuationState);
     298             :         }
     299           0 :         return NS_OK;
     300             :     }
     301             : 
     302           0 :     NS_IMETHODIMP Cancel(nsresult aReason) override
     303             :     {
     304             :         // Supposed to be called from main thread
     305           0 :         MOZ_ASSERT(NS_IsMainThread());
     306             : 
     307           0 :         mCancelled = true;
     308           0 :         return NS_OK;
     309             :     }
     310             : 
     311             : private:
     312             :     nsCOMPtr<nsIHttpAuthenticatorCallback> mCallback;
     313             :     char *mCreds; // This class owns it, freed in destructor
     314             :     uint32_t mFlags;
     315             :     nsresult mResult;
     316             :     bool mCancelled;
     317             :     nsCOMPtr<nsISupports> mSessionState;
     318             :     nsCOMPtr<nsISupports> mContinuationState;
     319             : };
     320             : 
     321           0 : NS_IMPL_ISUPPORTS(GetNextTokenCompleteEvent, nsIRunnable, nsICancelable)
     322             : 
     323             : //
     324             : // GetNextTokenRunnable
     325             : //
     326             : // This runnable is created by GenerateCredentialsAsync and it runs
     327             : // in nsHttpNegotiateAuth::mNegotiateThread and calling GenerateCredentials.
     328             : //
     329             : class GetNextTokenRunnable final : public mozilla::Runnable
     330             : {
     331           0 :     ~GetNextTokenRunnable() override = default;
     332             :     public:
     333           0 :       GetNextTokenRunnable(nsIHttpAuthenticableChannel* authChannel,
     334             :                            const char* challenge,
     335             :                            bool isProxyAuth,
     336             :                            const char16_t* domain,
     337             :                            const char16_t* username,
     338             :                            const char16_t* password,
     339             :                            nsISupports* sessionState,
     340             :                            nsISupports* continuationState,
     341             :                            GetNextTokenCompleteEvent* aCompleteEvent)
     342           0 :         : mozilla::Runnable("GetNextTokenRunnable")
     343             :         , mAuthChannel(authChannel)
     344             :         , mChallenge(challenge)
     345             :         , mIsProxyAuth(isProxyAuth)
     346             :         , mDomain(domain)
     347             :         , mUsername(username)
     348             :         , mPassword(password)
     349             :         , mSessionState(sessionState)
     350             :         , mContinuationState(continuationState)
     351           0 :         , mCompleteEvent(aCompleteEvent)
     352             :       {
     353           0 :         }
     354             : 
     355           0 :         NS_IMETHODIMP Run() override
     356             :         {
     357             :             // Runs on worker thread
     358           0 :             MOZ_ASSERT(!NS_IsMainThread());
     359             : 
     360             :             char *creds;
     361             :             uint32_t flags;
     362           0 :             nsresult rv = ObtainCredentialsAndFlags(&creds, &flags);
     363             : 
     364             :             // Passing session and continuation state this way to not touch
     365             :             // referencing of the object that may not be thread safe.
     366             :             // Not having a thread safe referencing doesn't mean the object
     367             :             // cannot be used on multiple threads (one example is nsAuthSSPI.)
     368             :             // This ensures state objects will be destroyed on the main thread
     369             :             // when not changed by GenerateCredentials.
     370           0 :             if (NS_FAILED(rv)) {
     371           0 :                 return mCompleteEvent->DispatchError(mSessionState.forget(),
     372           0 :                                                      mContinuationState.forget());
     373             :             }
     374             : 
     375           0 :             return mCompleteEvent->DispatchSuccess(creds, flags,
     376           0 :                                                    mSessionState.forget(),
     377           0 :                                                    mContinuationState.forget());
     378             :         }
     379             : 
     380           0 :         NS_IMETHODIMP ObtainCredentialsAndFlags(char **aCreds, uint32_t *aFlags)
     381             :         {
     382             :             nsresult rv;
     383             : 
     384             :             // Use negotiate service to call GenerateCredentials outside of main thread
     385           0 :             nsAutoCString contractId;
     386           0 :             contractId.Assign(NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX);
     387           0 :             contractId.Append("negotiate");
     388             :             nsCOMPtr<nsIHttpAuthenticator> authenticator =
     389           0 :               do_GetService(contractId.get(), &rv);
     390           0 :             NS_ENSURE_SUCCESS(rv, rv);
     391             : 
     392           0 :             nsISupports *sessionState = mSessionState;
     393           0 :             nsISupports *continuationState = mContinuationState;
     394             :             // The continuationState is for the sake of completeness propagated
     395             :             // to the caller (despite it is not changed in any GenerateCredentials
     396             :             // implementation).
     397             :             //
     398             :             // The only implementation that use sessionState is the
     399             :             // nsHttpDigestAuth::GenerateCredentials. Since there's no reason
     400             :             // to implement nsHttpDigestAuth::GenerateCredentialsAsync
     401             :             // because digest auth does not block the main thread, we won't
     402             :             // propagate changes to sessionState to the caller because of
     403             :             // the change is too complicated on the caller side.
     404             :             //
     405             :             // Should any of the session or continuation states change inside
     406             :             // this method, they must be threadsafe.
     407           0 :             rv = authenticator->GenerateCredentials(mAuthChannel,
     408             :                                                     mChallenge.get(),
     409           0 :                                                     mIsProxyAuth,
     410             :                                                     mDomain.get(),
     411             :                                                     mUsername.get(),
     412             :                                                     mPassword.get(),
     413             :                                                     &sessionState,
     414             :                                                     &continuationState,
     415             :                                                     aFlags,
     416           0 :                                                     aCreds);
     417           0 :             if (mSessionState != sessionState) {
     418           0 :                 mSessionState = sessionState;
     419             :             }
     420           0 :             if (mContinuationState != continuationState) {
     421           0 :                 mContinuationState = continuationState;
     422             :             }
     423           0 :             return rv;
     424             :         }
     425             :     private:
     426             :         nsCOMPtr<nsIHttpAuthenticableChannel> mAuthChannel;
     427             :         nsCString mChallenge;
     428             :         bool mIsProxyAuth;
     429             :         nsString mDomain;
     430             :         nsString mUsername;
     431             :         nsString mPassword;
     432             :         nsCOMPtr<nsISupports> mSessionState;
     433             :         nsCOMPtr<nsISupports> mContinuationState;
     434             :         RefPtr<GetNextTokenCompleteEvent> mCompleteEvent;
     435             : };
     436             : 
     437             : } // anonymous namespace
     438             : 
     439             : NS_IMETHODIMP
     440           0 : nsHttpNegotiateAuth::GenerateCredentialsAsync(nsIHttpAuthenticableChannel *authChannel,
     441             :                                               nsIHttpAuthenticatorCallback* aCallback,
     442             :                                               const char *challenge,
     443             :                                               bool isProxyAuth,
     444             :                                               const char16_t *domain,
     445             :                                               const char16_t *username,
     446             :                                               const char16_t *password,
     447             :                                               nsISupports *sessionState,
     448             :                                               nsISupports *continuationState,
     449             :                                               nsICancelable **aCancelable)
     450             : {
     451           0 :    NS_ENSURE_ARG(aCallback);
     452           0 :    NS_ENSURE_ARG_POINTER(aCancelable);
     453             : 
     454             :    RefPtr<GetNextTokenCompleteEvent> cancelEvent =
     455           0 :        new GetNextTokenCompleteEvent(aCallback);
     456             : 
     457             : 
     458             :    nsCOMPtr<nsIRunnable> getNextTokenRunnable =
     459             :        new GetNextTokenRunnable(authChannel,
     460             :                                 challenge,
     461             :                                 isProxyAuth,
     462             :                                 domain,
     463             :                                 username,
     464             :                                 password,
     465             :                                 sessionState,
     466             :                                 continuationState,
     467           0 :                                 cancelEvent);
     468           0 :    cancelEvent.forget(aCancelable);
     469             : 
     470             :    nsresult rv;
     471           0 :    if (!mNegotiateThread) {
     472             :        mNegotiateThread =
     473             :            new mozilla::LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
     474           0 :                                        NS_LITERAL_CSTRING("NegotiateAuth"));
     475           0 :        NS_ENSURE_TRUE(mNegotiateThread, NS_ERROR_OUT_OF_MEMORY);
     476             :    }
     477           0 :    rv = mNegotiateThread->Dispatch(getNextTokenRunnable, NS_DISPATCH_NORMAL);
     478           0 :    NS_ENSURE_SUCCESS(rv, rv);
     479             : 
     480           0 :    return NS_OK;
     481             : }
     482             : 
     483             : //
     484             : // GenerateCredentials
     485             : //
     486             : // This routine is responsible for creating the correct authentication
     487             : // blob to pass to the server that requested "Negotiate" authentication.
     488             : //
     489             : NS_IMETHODIMP
     490           0 : nsHttpNegotiateAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
     491             :                                          const char *challenge,
     492             :                                          bool isProxyAuth,
     493             :                                          const char16_t *domain,
     494             :                                          const char16_t *username,
     495             :                                          const char16_t *password,
     496             :                                          nsISupports **sessionState,
     497             :                                          nsISupports **continuationState,
     498             :                                          uint32_t *flags,
     499             :                                          char **creds)
     500             : {
     501             :     // ChallengeReceived must have been called previously.
     502           0 :     nsIAuthModule *module = (nsIAuthModule *) *continuationState;
     503           0 :     NS_ENSURE_TRUE(module, NS_ERROR_NOT_INITIALIZED);
     504             : 
     505           0 :     *flags = USING_INTERNAL_IDENTITY;
     506             : 
     507           0 :     LOG(("nsHttpNegotiateAuth::GenerateCredentials() [challenge=%s]\n", challenge));
     508             : 
     509           0 :     NS_ASSERTION(creds, "null param");
     510             : 
     511             : #ifdef DEBUG
     512             :     bool isGssapiAuth =
     513           0 :         !PL_strncasecmp(challenge, kNegotiate, kNegotiateLen);
     514           0 :     NS_ASSERTION(isGssapiAuth, "Unexpected challenge");
     515             : #endif
     516             : 
     517             :     //
     518             :     // If the "Negotiate:" header had some data associated with it,
     519             :     // that data should be used as the input to this call.  This may
     520             :     // be a continuation of an earlier call because GSSAPI authentication
     521             :     // often takes multiple round-trips to complete depending on the
     522             :     // context flags given.  We want to use MUTUAL_AUTHENTICATION which
     523             :     // generally *does* require multiple round-trips.  Don't assume
     524             :     // auth can be completed in just 1 call.
     525             :     //
     526           0 :     unsigned int len = strlen(challenge);
     527             : 
     528           0 :     void *inToken = nullptr, *outToken;
     529             :     uint32_t inTokenLen, outTokenLen;
     530             : 
     531           0 :     if (len > kNegotiateLen) {
     532           0 :         challenge += kNegotiateLen;
     533           0 :         while (*challenge == ' ')
     534           0 :             challenge++;
     535           0 :         len = strlen(challenge);
     536             : 
     537             :         // strip off any padding (see bug 230351)
     538           0 :         while (challenge[len - 1] == '=')
     539           0 :             len--;
     540             : 
     541             :         //
     542             :         // Decode the response that followed the "Negotiate" token
     543             :         //
     544             :         nsresult rv =
     545           0 :             Base64Decode(challenge, len, (char**)&inToken, &inTokenLen);
     546             : 
     547           0 :         if (NS_FAILED(rv)) {
     548           0 :             free(inToken);
     549           0 :             return rv;
     550             :         }
     551             :     }
     552             :     else {
     553             :         //
     554             :         // Initializing, don't use an input token.
     555             :         //
     556           0 :         inTokenLen = 0;
     557             :     }
     558             : 
     559           0 :     nsresult rv = module->GetNextToken(inToken, inTokenLen, &outToken, &outTokenLen);
     560             : 
     561           0 :     free(inToken);
     562             : 
     563           0 :     if (NS_FAILED(rv))
     564           0 :         return rv;
     565             : 
     566           0 :     if (outTokenLen == 0) {
     567           0 :         LOG(("  No output token to send, exiting"));
     568           0 :         return NS_ERROR_FAILURE;
     569             :     }
     570             : 
     571             :     //
     572             :     // base64 encode the output token.
     573             :     //
     574           0 :     char *encoded_token = PL_Base64Encode((char *)outToken, outTokenLen, nullptr);
     575             : 
     576           0 :     free(outToken);
     577             : 
     578           0 :     if (!encoded_token)
     579           0 :         return NS_ERROR_OUT_OF_MEMORY;
     580             : 
     581           0 :     LOG(("  Sending a token of length %d\n", outTokenLen));
     582             : 
     583             :     // allocate a buffer sizeof("Negotiate" + " " + b64output_token + "\0")
     584           0 :     const int bufsize = kNegotiateLen + 1 + strlen(encoded_token) + 1;
     585           0 :     *creds = (char *) moz_xmalloc(bufsize);
     586           0 :     if (MOZ_UNLIKELY(!*creds))
     587           0 :         rv = NS_ERROR_OUT_OF_MEMORY;
     588             :     else
     589           0 :         snprintf(*creds, bufsize, "%s %s", kNegotiate, encoded_token);
     590             : 
     591           0 :     PR_Free(encoded_token); // PL_Base64Encode() uses PR_Malloc().
     592           0 :     return rv;
     593             : }
     594             : 
     595             : bool
     596           0 : nsHttpNegotiateAuth::TestBoolPref(const char *pref)
     597             : {
     598           0 :     nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
     599           0 :     if (!prefs)
     600           0 :         return false;
     601             : 
     602             :     bool val;
     603           0 :     nsresult rv = prefs->GetBoolPref(pref, &val);
     604           0 :     if (NS_FAILED(rv))
     605           0 :         return false;
     606             : 
     607           0 :     return val;
     608             : }
     609             : 
     610             : bool
     611           0 : nsHttpNegotiateAuth::TestNonFqdn(nsIURI *uri)
     612             : {
     613           0 :     nsAutoCString host;
     614             :     PRNetAddr addr;
     615             : 
     616           0 :     if (!TestBoolPref(kNegotiateAuthAllowNonFqdn))
     617           0 :         return false;
     618             : 
     619           0 :     if (NS_FAILED(uri->GetAsciiHost(host)))
     620           0 :         return false;
     621             : 
     622             :     // return true if host does not contain a dot and is not an ip address
     623           0 :     return !host.IsEmpty() && !host.Contains('.') &&
     624           0 :            PR_StringToNetAddr(host.BeginReading(), &addr) != PR_SUCCESS;
     625             : }

Generated by: LCOV version 1.13