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 : }
|