Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/extensions/auth/nsHttpNegotiateAuth.cpp
Line
Count
Source (jump to first uncovered line)
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
0
#define kNegotiateLen  (sizeof(kNegotiate)-1)
66
0
#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
TestNotInPBMode(nsIHttpAuthenticableChannel *authChannel, bool proxyAuth)
73
0
{
74
0
    // Proxy should go all the time, it's not considered a privacy leak
75
0
    // to send default credentials to a proxy.
76
0
    if (proxyAuth) {
77
0
        return true;
78
0
    }
79
0
80
0
    nsCOMPtr<nsIChannel> bareChannel = do_QueryInterface(authChannel);
81
0
    MOZ_ASSERT(bareChannel);
82
0
83
0
    if (!NS_UsePrivateBrowsing(bareChannel)) {
84
0
        return true;
85
0
    }
86
0
87
0
    nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
88
0
    if (prefs) {
89
0
        bool ssoInPb;
90
0
        if (NS_SUCCEEDED(prefs->GetBoolPref(kSSOinPBmode, &ssoInPb)) && ssoInPb) {
91
0
            return true;
92
0
        }
93
0
94
0
        // When the "Never remember history" option is set, all channels are
95
0
        // set PB mode flag, but here we want to make an exception, users
96
0
        // want their credentials go out.
97
0
        bool dontRememberHistory;
98
0
        if (NS_SUCCEEDED(prefs->GetBoolPref("browser.privatebrowsing.autostart",
99
0
                                            &dontRememberHistory)) &&
100
0
            dontRememberHistory) {
101
0
            return true;
102
0
        }
103
0
    }
104
0
105
0
    return false;
106
0
}
107
108
NS_IMETHODIMP
109
nsHttpNegotiateAuth::GetAuthFlags(uint32_t *flags)
110
0
{
111
0
    //
112
0
    // Negotiate Auth creds should not be reused across multiple requests.
113
0
    // Only perform the negotiation when it is explicitly requested by the
114
0
    // server.  Thus, do *NOT* use the "REUSABLE_CREDENTIALS" flag here.
115
0
    //
116
0
    // CONNECTION_BASED is specified instead of REQUEST_BASED since we need
117
0
    // to complete a sequence of transactions with the server over the same
118
0
    // connection.
119
0
    //
120
0
    *flags = CONNECTION_BASED | IDENTITY_IGNORED;
121
0
    return NS_OK;
122
0
}
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
nsHttpNegotiateAuth::ChallengeReceived(nsIHttpAuthenticableChannel *authChannel,
133
                                       const char *challenge,
134
                                       bool isProxyAuth,
135
                                       nsISupports **sessionState,
136
                                       nsISupports **continuationState,
137
                                       bool *identityInvalid)
138
0
{
139
0
    nsIAuthModule *module = (nsIAuthModule *) *continuationState;
140
0
141
0
    *identityInvalid = false;
142
0
    if (module)
143
0
        return NS_OK;
144
0
145
0
    nsresult rv;
146
0
147
0
    nsCOMPtr<nsIURI> uri;
148
0
    rv = authChannel->GetURI(getter_AddRefs(uri));
149
0
    if (NS_FAILED(rv))
150
0
        return rv;
151
0
152
0
    uint32_t req_flags = nsIAuthModule::REQ_DEFAULT;
153
0
    nsAutoCString service;
154
0
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
0
        }
160
0
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
0
166
0
        proxyInfo->GetHost(service);
167
0
    }
168
0
    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
0
        }
176
0
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
0
        }
182
0
183
0
        rv = uri->GetAsciiHost(service);
184
0
        if (NS_FAILED(rv))
185
0
            return rv;
186
0
    }
187
0
188
0
    LOG(("  service = %s\n", service.get()));
189
0
190
0
    //
191
0
    // The correct service name for IIS servers is "HTTP/f.q.d.n", so
192
0
    // construct the proper service name for passing to "gss_import_name".
193
0
    //
194
0
    // TODO: Possibly make this a configurable service name for use
195
0
    // with non-standard servers that use stuff like "khttp/f.q.d.n"
196
0
    // instead.
197
0
    //
198
0
    service.InsertLiteral("HTTP@", 0);
199
0
200
0
    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
0
    }
205
0
    else {
206
0
     LOG(("  using negotiate-gss\n"));
207
0
     contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-gss";
208
0
    }
209
0
210
0
    rv = CallCreateInstance(contractID, &module);
211
0
212
0
    if (NS_FAILED(rv)) {
213
0
        LOG(("  Failed to load Negotiate Module \n"));
214
0
        return rv;
215
0
    }
216
0
217
0
    rv = module->Init(service.get(), req_flags, nullptr, nullptr, nullptr);
218
0
219
0
    if (NS_FAILED(rv)) {
220
0
        NS_RELEASE(module);
221
0
        return rv;
222
0
    }
223
0
224
0
    *continuationState = module;
225
0
    return NS_OK;
226
0
}
227
228
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
    virtual ~GetNextTokenCompleteEvent()
245
0
    {
246
0
        if (mCreds) {
247
0
            free(mCreds);
248
0
        }
249
0
    };
250
251
public:
252
    NS_DECL_THREADSAFE_ISUPPORTS
253
254
    explicit GetNextTokenCompleteEvent(nsIHttpAuthenticatorCallback* aCallback)
255
        : mCallback(aCallback)
256
        , mCreds(nullptr)
257
        , mCancelled(false)
258
0
    {
259
0
    }
260
261
    NS_IMETHODIMP DispatchSuccess(char *aCreds,
262
                                  uint32_t aFlags,
263
                                  already_AddRefed<nsISupports> aSessionState,
264
                                  already_AddRefed<nsISupports> aContinuationState)
265
0
    {
266
0
        // Called from worker thread
267
0
        MOZ_ASSERT(!NS_IsMainThread());
268
0
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
0
    }
276
277
    NS_IMETHODIMP DispatchError(already_AddRefed<nsISupports> aSessionState,
278
                                already_AddRefed<nsISupports> aContinuationState)
279
0
    {
280
0
        // Called from worker thread
281
0
        MOZ_ASSERT(!NS_IsMainThread());
282
0
283
0
        mResult = NS_ERROR_FAILURE;
284
0
        mSessionState = aSessionState;
285
0
        mContinuationState = aContinuationState;
286
0
        return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
287
0
    }
288
289
    NS_IMETHODIMP Run() override
290
0
    {
291
0
        // Runs on main thread
292
0
        MOZ_ASSERT(NS_IsMainThread());
293
0
294
0
        if (!mCancelled) {
295
0
            nsCOMPtr<nsIHttpAuthenticatorCallback> callback;
296
0
            callback.swap(mCallback);
297
0
            callback->OnCredsGenerated(mCreds, mFlags, mResult, mSessionState, mContinuationState);
298
0
        }
299
0
        return NS_OK;
300
0
    }
301
302
    NS_IMETHODIMP Cancel(nsresult aReason) override
303
0
    {
304
0
        // Supposed to be called from main thread
305
0
        MOZ_ASSERT(NS_IsMainThread());
306
0
307
0
        mCancelled = true;
308
0
        return NS_OK;
309
0
    }
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
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
      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
        : 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
        , mCompleteEvent(aCompleteEvent)
352
0
      {
353
0
        }
354
355
        NS_IMETHODIMP Run() override
356
0
        {
357
0
            // Runs on worker thread
358
0
            MOZ_ASSERT(!NS_IsMainThread());
359
0
360
0
            char *creds;
361
0
            uint32_t flags;
362
0
            nsresult rv = ObtainCredentialsAndFlags(&creds, &flags);
363
0
364
0
            // Passing session and continuation state this way to not touch
365
0
            // referencing of the object that may not be thread safe.
366
0
            // Not having a thread safe referencing doesn't mean the object
367
0
            // cannot be used on multiple threads (one example is nsAuthSSPI.)
368
0
            // This ensures state objects will be destroyed on the main thread
369
0
            // when not changed by GenerateCredentials.
370
0
            if (NS_FAILED(rv)) {
371
0
                return mCompleteEvent->DispatchError(mSessionState.forget(),
372
0
                                                     mContinuationState.forget());
373
0
            }
374
0
375
0
            return mCompleteEvent->DispatchSuccess(creds, flags,
376
0
                                                   mSessionState.forget(),
377
0
                                                   mContinuationState.forget());
378
0
        }
379
380
        NS_IMETHODIMP ObtainCredentialsAndFlags(char **aCreds, uint32_t *aFlags)
381
0
        {
382
0
            nsresult rv;
383
0
384
0
            // Use negotiate service to call GenerateCredentials outside of main thread
385
0
            nsAutoCString contractId;
386
0
            contractId.AssignLiteral(NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX);
387
0
            contractId.AppendLiteral("negotiate");
388
0
            nsCOMPtr<nsIHttpAuthenticator> authenticator =
389
0
              do_GetService(contractId.get(), &rv);
390
0
            NS_ENSURE_SUCCESS(rv, rv);
391
0
392
0
            nsISupports *sessionState = mSessionState;
393
0
            nsISupports *continuationState = mContinuationState;
394
0
            // The continuationState is for the sake of completeness propagated
395
0
            // to the caller (despite it is not changed in any GenerateCredentials
396
0
            // implementation).
397
0
            //
398
0
            // The only implementation that use sessionState is the
399
0
            // nsHttpDigestAuth::GenerateCredentials. Since there's no reason
400
0
            // to implement nsHttpDigestAuth::GenerateCredentialsAsync
401
0
            // because digest auth does not block the main thread, we won't
402
0
            // propagate changes to sessionState to the caller because of
403
0
            // the change is too complicated on the caller side.
404
0
            //
405
0
            // Should any of the session or continuation states change inside
406
0
            // this method, they must be threadsafe.
407
0
            rv = authenticator->GenerateCredentials(mAuthChannel,
408
0
                                                    mChallenge.get(),
409
0
                                                    mIsProxyAuth,
410
0
                                                    mDomain.get(),
411
0
                                                    mUsername.get(),
412
0
                                                    mPassword.get(),
413
0
                                                    &sessionState,
414
0
                                                    &continuationState,
415
0
                                                    aFlags,
416
0
                                                    aCreds);
417
0
            if (mSessionState != sessionState) {
418
0
                mSessionState = sessionState;
419
0
            }
420
0
            if (mContinuationState != continuationState) {
421
0
                mContinuationState = continuationState;
422
0
            }
423
0
            return rv;
424
0
        }
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
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
0
{
451
0
   NS_ENSURE_ARG(aCallback);
452
0
   NS_ENSURE_ARG_POINTER(aCancelable);
453
0
454
0
   RefPtr<GetNextTokenCompleteEvent> cancelEvent =
455
0
       new GetNextTokenCompleteEvent(aCallback);
456
0
457
0
458
0
   nsCOMPtr<nsIRunnable> getNextTokenRunnable =
459
0
       new GetNextTokenRunnable(authChannel,
460
0
                                challenge,
461
0
                                isProxyAuth,
462
0
                                domain,
463
0
                                username,
464
0
                                password,
465
0
                                sessionState,
466
0
                                continuationState,
467
0
                                cancelEvent);
468
0
   cancelEvent.forget(aCancelable);
469
0
470
0
   nsresult rv;
471
0
   if (!mNegotiateThread) {
472
0
       mNegotiateThread =
473
0
           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
0
   }
477
0
   rv = mNegotiateThread->Dispatch(getNextTokenRunnable, NS_DISPATCH_NORMAL);
478
0
   NS_ENSURE_SUCCESS(rv, rv);
479
0
480
0
   return NS_OK;
481
0
}
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
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
0
{
501
0
    // ChallengeReceived must have been called previously.
502
0
    nsIAuthModule *module = (nsIAuthModule *) *continuationState;
503
0
    NS_ENSURE_TRUE(module, NS_ERROR_NOT_INITIALIZED);
504
0
505
0
    *flags = USING_INTERNAL_IDENTITY;
506
0
507
0
    LOG(("nsHttpNegotiateAuth::GenerateCredentials() [challenge=%s]\n", challenge));
508
0
509
0
    NS_ASSERTION(creds, "null param");
510
0
511
#ifdef DEBUG
512
    bool isGssapiAuth =
513
        !PL_strncasecmp(challenge, kNegotiate, kNegotiateLen);
514
    NS_ASSERTION(isGssapiAuth, "Unexpected challenge");
515
#endif
516
517
0
    //
518
0
    // If the "Negotiate:" header had some data associated with it,
519
0
    // that data should be used as the input to this call.  This may
520
0
    // be a continuation of an earlier call because GSSAPI authentication
521
0
    // often takes multiple round-trips to complete depending on the
522
0
    // context flags given.  We want to use MUTUAL_AUTHENTICATION which
523
0
    // generally *does* require multiple round-trips.  Don't assume
524
0
    // auth can be completed in just 1 call.
525
0
    //
526
0
    unsigned int len = strlen(challenge);
527
0
528
0
    void *inToken = nullptr, *outToken;
529
0
    uint32_t inTokenLen, outTokenLen;
530
0
531
0
    if (len > kNegotiateLen) {
532
0
        challenge += kNegotiateLen;
533
0
        while (*challenge == ' ')
534
0
            challenge++;
535
0
        len = strlen(challenge);
536
0
537
0
        // strip off any padding (see bug 230351)
538
0
        while (challenge[len - 1] == '=')
539
0
            len--;
540
0
541
0
        //
542
0
        // Decode the response that followed the "Negotiate" token
543
0
        //
544
0
        nsresult rv =
545
0
            Base64Decode(challenge, len, (char**)&inToken, &inTokenLen);
546
0
547
0
        if (NS_FAILED(rv)) {
548
0
            free(inToken);
549
0
            return rv;
550
0
        }
551
0
    }
552
0
    else {
553
0
        //
554
0
        // Initializing, don't use an input token.
555
0
        //
556
0
        inTokenLen = 0;
557
0
    }
558
0
559
0
    nsresult rv = module->GetNextToken(inToken, inTokenLen, &outToken, &outTokenLen);
560
0
561
0
    free(inToken);
562
0
563
0
    if (NS_FAILED(rv))
564
0
        return rv;
565
0
566
0
    if (outTokenLen == 0) {
567
0
        LOG(("  No output token to send, exiting"));
568
0
        return NS_ERROR_FAILURE;
569
0
    }
570
0
571
0
    //
572
0
    // base64 encode the output token.
573
0
    //
574
0
    char *encoded_token = PL_Base64Encode((char *)outToken, outTokenLen, nullptr);
575
0
576
0
    free(outToken);
577
0
578
0
    if (!encoded_token)
579
0
        return NS_ERROR_OUT_OF_MEMORY;
580
0
581
0
    LOG(("  Sending a token of length %d\n", outTokenLen));
582
0
583
0
    // 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
    snprintf(*creds, bufsize, "%s %s", kNegotiate, encoded_token);
587
0
588
0
    PR_Free(encoded_token); // PL_Base64Encode() uses PR_Malloc().
589
0
    return rv;
590
0
}
591
592
bool
593
nsHttpNegotiateAuth::TestBoolPref(const char *pref)
594
0
{
595
0
    nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
596
0
    if (!prefs)
597
0
        return false;
598
0
599
0
    bool val;
600
0
    nsresult rv = prefs->GetBoolPref(pref, &val);
601
0
    if (NS_FAILED(rv))
602
0
        return false;
603
0
604
0
    return val;
605
0
}
606
607
bool
608
nsHttpNegotiateAuth::TestNonFqdn(nsIURI *uri)
609
0
{
610
0
    nsAutoCString host;
611
0
    PRNetAddr addr;
612
0
613
0
    if (!TestBoolPref(kNegotiateAuthAllowNonFqdn))
614
0
        return false;
615
0
616
0
    if (NS_FAILED(uri->GetAsciiHost(host)))
617
0
        return false;
618
0
619
0
    // return true if host does not contain a dot and is not an ip address
620
0
    return !host.IsEmpty() && !host.Contains('.') &&
621
0
           PR_StringToNetAddr(host.BeginReading(), &addr) != PR_SUCCESS;
622
0
}