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