netwerk/protocol/http/nsHttpNTLMAuth.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

michael@0 1 /* vim:set ts=4 sw=4 sts=4 et ci: */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 // HttpLog.h should generally be included first
michael@0 7 #include "HttpLog.h"
michael@0 8
michael@0 9 #include "nsHttpNTLMAuth.h"
michael@0 10 #include "nsIAuthModule.h"
michael@0 11 #include "nsCOMPtr.h"
michael@0 12 #include "plbase64.h"
michael@0 13 #include "prnetdb.h"
michael@0 14
michael@0 15 //-----------------------------------------------------------------------------
michael@0 16
michael@0 17 #include "nsIPrefBranch.h"
michael@0 18 #include "nsIPrefService.h"
michael@0 19 #include "nsIHttpAuthenticableChannel.h"
michael@0 20 #include "nsIURI.h"
michael@0 21 #ifdef XP_WIN
michael@0 22 #include "nsIX509Cert.h"
michael@0 23 #include "nsISSLStatus.h"
michael@0 24 #include "nsISSLStatusProvider.h"
michael@0 25 #endif
michael@0 26 #include "mozilla/Attributes.h"
michael@0 27 #include "nsThreadUtils.h"
michael@0 28
michael@0 29 namespace mozilla {
michael@0 30 namespace net {
michael@0 31
michael@0 32 static const char kAllowProxies[] = "network.automatic-ntlm-auth.allow-proxies";
michael@0 33 static const char kAllowNonFqdn[] = "network.automatic-ntlm-auth.allow-non-fqdn";
michael@0 34 static const char kTrustedURIs[] = "network.automatic-ntlm-auth.trusted-uris";
michael@0 35 static const char kForceGeneric[] = "network.auth.force-generic-ntlm";
michael@0 36 static const char kAllowGenericHTTP[] = "network.negotiate-auth.allow-insecure-ntlm-v1";
michael@0 37 static const char kAllowGenericHTTPS[] = "network.negotiate-auth.allow-insecure-ntlm-v1-https";
michael@0 38
michael@0 39 // XXX MatchesBaseURI and TestPref are duplicated in nsHttpNegotiateAuth.cpp,
michael@0 40 // but since that file lives in a separate library we cannot directly share it.
michael@0 41 // bug 236865 addresses this problem.
michael@0 42
michael@0 43 static bool
michael@0 44 MatchesBaseURI(const nsCSubstring &matchScheme,
michael@0 45 const nsCSubstring &matchHost,
michael@0 46 int32_t matchPort,
michael@0 47 const char *baseStart,
michael@0 48 const char *baseEnd)
michael@0 49 {
michael@0 50 // check if scheme://host:port matches baseURI
michael@0 51
michael@0 52 // parse the base URI
michael@0 53 const char *hostStart, *schemeEnd = strstr(baseStart, "://");
michael@0 54 if (schemeEnd) {
michael@0 55 // the given scheme must match the parsed scheme exactly
michael@0 56 if (!matchScheme.Equals(Substring(baseStart, schemeEnd)))
michael@0 57 return false;
michael@0 58 hostStart = schemeEnd + 3;
michael@0 59 }
michael@0 60 else
michael@0 61 hostStart = baseStart;
michael@0 62
michael@0 63 // XXX this does not work for IPv6-literals
michael@0 64 const char *hostEnd = strchr(hostStart, ':');
michael@0 65 if (hostEnd && hostEnd < baseEnd) {
michael@0 66 // the given port must match the parsed port exactly
michael@0 67 int port = atoi(hostEnd + 1);
michael@0 68 if (matchPort != (int32_t) port)
michael@0 69 return false;
michael@0 70 }
michael@0 71 else
michael@0 72 hostEnd = baseEnd;
michael@0 73
michael@0 74
michael@0 75 // if we didn't parse out a host, then assume we got a match.
michael@0 76 if (hostStart == hostEnd)
michael@0 77 return true;
michael@0 78
michael@0 79 uint32_t hostLen = hostEnd - hostStart;
michael@0 80
michael@0 81 // matchHost must either equal host or be a subdomain of host
michael@0 82 if (matchHost.Length() < hostLen)
michael@0 83 return false;
michael@0 84
michael@0 85 const char *end = matchHost.EndReading();
michael@0 86 if (PL_strncasecmp(end - hostLen, hostStart, hostLen) == 0) {
michael@0 87 // if matchHost ends with host from the base URI, then make sure it is
michael@0 88 // either an exact match, or prefixed with a dot. we don't want
michael@0 89 // "foobar.com" to match "bar.com"
michael@0 90 if (matchHost.Length() == hostLen ||
michael@0 91 *(end - hostLen) == '.' ||
michael@0 92 *(end - hostLen - 1) == '.')
michael@0 93 return true;
michael@0 94 }
michael@0 95
michael@0 96 return false;
michael@0 97 }
michael@0 98
michael@0 99 static bool
michael@0 100 IsNonFqdn(nsIURI *uri)
michael@0 101 {
michael@0 102 nsAutoCString host;
michael@0 103 PRNetAddr addr;
michael@0 104
michael@0 105 if (NS_FAILED(uri->GetAsciiHost(host)))
michael@0 106 return false;
michael@0 107
michael@0 108 // return true if host does not contain a dot and is not an ip address
michael@0 109 return !host.IsEmpty() && host.FindChar('.') == kNotFound &&
michael@0 110 PR_StringToNetAddr(host.BeginReading(), &addr) != PR_SUCCESS;
michael@0 111 }
michael@0 112
michael@0 113 static bool
michael@0 114 TestPref(nsIURI *uri, const char *pref)
michael@0 115 {
michael@0 116 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
michael@0 117 if (!prefs)
michael@0 118 return false;
michael@0 119
michael@0 120 nsAutoCString scheme, host;
michael@0 121 int32_t port;
michael@0 122
michael@0 123 if (NS_FAILED(uri->GetScheme(scheme)))
michael@0 124 return false;
michael@0 125 if (NS_FAILED(uri->GetAsciiHost(host)))
michael@0 126 return false;
michael@0 127 if (NS_FAILED(uri->GetPort(&port)))
michael@0 128 return false;
michael@0 129
michael@0 130 char *hostList;
michael@0 131 if (NS_FAILED(prefs->GetCharPref(pref, &hostList)) || !hostList)
michael@0 132 return false;
michael@0 133
michael@0 134 // pseudo-BNF
michael@0 135 // ----------
michael@0 136 //
michael@0 137 // url-list base-url ( base-url "," LWS )*
michael@0 138 // base-url ( scheme-part | host-part | scheme-part host-part )
michael@0 139 // scheme-part scheme "://"
michael@0 140 // host-part host [":" port]
michael@0 141 //
michael@0 142 // for example:
michael@0 143 // "https://, http://office.foo.com"
michael@0 144 //
michael@0 145
michael@0 146 char *start = hostList, *end;
michael@0 147 for (;;) {
michael@0 148 // skip past any whitespace
michael@0 149 while (*start == ' ' || *start == '\t')
michael@0 150 ++start;
michael@0 151 end = strchr(start, ',');
michael@0 152 if (!end)
michael@0 153 end = start + strlen(start);
michael@0 154 if (start == end)
michael@0 155 break;
michael@0 156 if (MatchesBaseURI(scheme, host, port, start, end))
michael@0 157 return true;
michael@0 158 if (*end == '\0')
michael@0 159 break;
michael@0 160 start = end + 1;
michael@0 161 }
michael@0 162
michael@0 163 nsMemory::Free(hostList);
michael@0 164 return false;
michael@0 165 }
michael@0 166
michael@0 167 // Check to see if we should use our generic (internal) NTLM auth module.
michael@0 168 static bool
michael@0 169 ForceGenericNTLM()
michael@0 170 {
michael@0 171 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
michael@0 172 if (!prefs)
michael@0 173 return false;
michael@0 174 bool flag = false;
michael@0 175
michael@0 176 if (NS_FAILED(prefs->GetBoolPref(kForceGeneric, &flag)))
michael@0 177 flag = false;
michael@0 178
michael@0 179 LOG(("Force use of generic ntlm auth module: %d\n", flag));
michael@0 180 return flag;
michael@0 181 }
michael@0 182
michael@0 183 // Check to see if we should use our generic (internal) NTLM auth module.
michael@0 184 static bool
michael@0 185 AllowGenericNTLM()
michael@0 186 {
michael@0 187 MOZ_ASSERT(NS_IsMainThread());
michael@0 188
michael@0 189 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
michael@0 190 if (!prefs)
michael@0 191 return false;
michael@0 192
michael@0 193 bool flag = false;
michael@0 194 if (NS_FAILED(prefs->GetBoolPref(kAllowGenericHTTP, &flag)))
michael@0 195 flag = false;
michael@0 196
michael@0 197 LOG(("Allow use of generic ntlm auth module: %d\n", flag));
michael@0 198 return flag;
michael@0 199 }
michael@0 200
michael@0 201 // Check to see if we should use our generic (internal) NTLM auth module.
michael@0 202 static bool
michael@0 203 AllowGenericNTLMforHTTPS(nsIHttpAuthenticableChannel *channel)
michael@0 204 {
michael@0 205 bool isSSL = false;
michael@0 206 channel->GetIsSSL(&isSSL);
michael@0 207 if (!isSSL)
michael@0 208 return false;
michael@0 209
michael@0 210 MOZ_ASSERT(NS_IsMainThread());
michael@0 211
michael@0 212 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
michael@0 213 if (!prefs)
michael@0 214 return false;
michael@0 215
michael@0 216 bool flag = false;
michael@0 217 if (NS_FAILED(prefs->GetBoolPref(kAllowGenericHTTPS, &flag)))
michael@0 218 flag = false;
michael@0 219
michael@0 220 LOG(("Allow use of generic ntlm auth module for only https: %d\n", flag));
michael@0 221 return flag;
michael@0 222 }
michael@0 223
michael@0 224 // Check to see if we should use default credentials for this host or proxy.
michael@0 225 static bool
michael@0 226 CanUseDefaultCredentials(nsIHttpAuthenticableChannel *channel,
michael@0 227 bool isProxyAuth)
michael@0 228 {
michael@0 229 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
michael@0 230 if (!prefs)
michael@0 231 return false;
michael@0 232
michael@0 233 if (isProxyAuth) {
michael@0 234 bool val;
michael@0 235 if (NS_FAILED(prefs->GetBoolPref(kAllowProxies, &val)))
michael@0 236 val = false;
michael@0 237 LOG(("Default credentials allowed for proxy: %d\n", val));
michael@0 238 return val;
michael@0 239 }
michael@0 240
michael@0 241 nsCOMPtr<nsIURI> uri;
michael@0 242 channel->GetURI(getter_AddRefs(uri));
michael@0 243
michael@0 244 bool allowNonFqdn;
michael@0 245 if (NS_FAILED(prefs->GetBoolPref(kAllowNonFqdn, &allowNonFqdn)))
michael@0 246 allowNonFqdn = false;
michael@0 247 if (allowNonFqdn && uri && IsNonFqdn(uri)) {
michael@0 248 LOG(("Host is non-fqdn, default credentials are allowed\n"));
michael@0 249 return true;
michael@0 250 }
michael@0 251
michael@0 252 bool isTrustedHost = (uri && TestPref(uri, kTrustedURIs));
michael@0 253 LOG(("Default credentials allowed for host: %d\n", isTrustedHost));
michael@0 254 return isTrustedHost;
michael@0 255 }
michael@0 256
michael@0 257 // Dummy class for session state object. This class doesn't hold any data.
michael@0 258 // Instead we use its existence as a flag. See ChallengeReceived.
michael@0 259 class nsNTLMSessionState MOZ_FINAL : public nsISupports
michael@0 260 {
michael@0 261 public:
michael@0 262 NS_DECL_ISUPPORTS
michael@0 263 };
michael@0 264 NS_IMPL_ISUPPORTS0(nsNTLMSessionState)
michael@0 265
michael@0 266 //-----------------------------------------------------------------------------
michael@0 267
michael@0 268 NS_IMPL_ISUPPORTS(nsHttpNTLMAuth, nsIHttpAuthenticator)
michael@0 269
michael@0 270 NS_IMETHODIMP
michael@0 271 nsHttpNTLMAuth::ChallengeReceived(nsIHttpAuthenticableChannel *channel,
michael@0 272 const char *challenge,
michael@0 273 bool isProxyAuth,
michael@0 274 nsISupports **sessionState,
michael@0 275 nsISupports **continuationState,
michael@0 276 bool *identityInvalid)
michael@0 277 {
michael@0 278 LOG(("nsHttpNTLMAuth::ChallengeReceived [ss=%p cs=%p]\n",
michael@0 279 *sessionState, *continuationState));
michael@0 280
michael@0 281 // Use the native NTLM if available
michael@0 282 mUseNative = true;
michael@0 283
michael@0 284 // NOTE: we don't define any session state, but we do use the pointer.
michael@0 285
michael@0 286 *identityInvalid = false;
michael@0 287
michael@0 288 /* Always fail Negotiate auth for Tor Browser. We don't need it. */
michael@0 289 return NS_ERROR_ABORT;
michael@0 290
michael@0 291 // Start a new auth sequence if the challenge is exactly "NTLM".
michael@0 292 // If native NTLM auth apis are available and enabled through prefs,
michael@0 293 // try to use them.
michael@0 294 if (PL_strcasecmp(challenge, "NTLM") == 0) {
michael@0 295 nsCOMPtr<nsISupports> module;
michael@0 296
michael@0 297 // Check to see if we should default to our generic NTLM auth module
michael@0 298 // through UseGenericNTLM. (We use native auth by default if the
michael@0 299 // system provides it.) If *sessionState is non-null, we failed to
michael@0 300 // instantiate a native NTLM module the last time, so skip trying again.
michael@0 301 bool forceGeneric = ForceGenericNTLM();
michael@0 302 if (!forceGeneric && !*sessionState) {
michael@0 303 // Check for approved default credentials hosts and proxies. If
michael@0 304 // *continuationState is non-null, the last authentication attempt
michael@0 305 // failed so skip default credential use.
michael@0 306 if (!*continuationState && CanUseDefaultCredentials(channel, isProxyAuth)) {
michael@0 307 // Try logging in with the user's default credentials. If
michael@0 308 // successful, |identityInvalid| is false, which will trigger
michael@0 309 // a default credentials attempt once we return.
michael@0 310 module = do_CreateInstance(NS_AUTH_MODULE_CONTRACTID_PREFIX "sys-ntlm");
michael@0 311 }
michael@0 312 #ifdef XP_WIN
michael@0 313 else {
michael@0 314 // Try to use native NTLM and prompt the user for their domain,
michael@0 315 // username, and password. (only supported by windows nsAuthSSPI module.)
michael@0 316 // Note, for servers that use LMv1 a weak hash of the user's password
michael@0 317 // will be sent. We rely on windows internal apis to decide whether
michael@0 318 // we should support this older, less secure version of the protocol.
michael@0 319 module = do_CreateInstance(NS_AUTH_MODULE_CONTRACTID_PREFIX "sys-ntlm");
michael@0 320 *identityInvalid = true;
michael@0 321 }
michael@0 322 #endif // XP_WIN
michael@0 323 #ifdef PR_LOGGING
michael@0 324 if (!module)
michael@0 325 LOG(("Native sys-ntlm auth module not found.\n"));
michael@0 326 #endif
michael@0 327 }
michael@0 328
michael@0 329 #ifdef XP_WIN
michael@0 330 // On windows, never fall back unless the user has specifically requested so.
michael@0 331 if (!forceGeneric && !module)
michael@0 332 return NS_ERROR_UNEXPECTED;
michael@0 333 #endif
michael@0 334
michael@0 335 // If no native support was available. Fall back on our internal NTLM implementation.
michael@0 336 if (!module) {
michael@0 337 if (!*sessionState) {
michael@0 338 // Remember the fact that we cannot use the "sys-ntlm" module,
michael@0 339 // so we don't ever bother trying again for this auth domain.
michael@0 340 *sessionState = new nsNTLMSessionState();
michael@0 341 if (!*sessionState)
michael@0 342 return NS_ERROR_OUT_OF_MEMORY;
michael@0 343 NS_ADDREF(*sessionState);
michael@0 344 }
michael@0 345
michael@0 346 // Use our internal NTLM implementation. Note, this is less secure,
michael@0 347 // see bug 520607 for details.
michael@0 348
michael@0 349 // For now with default preference settings (i.e. allow-insecure-ntlm-v1-https = true
michael@0 350 // and allow-insecure-ntlm-v1 = false) we don't allow authentication to any proxy,
michael@0 351 // either http or https. This will be fixed in a followup bug.
michael@0 352 if (AllowGenericNTLM() || (!isProxyAuth && AllowGenericNTLMforHTTPS(channel))) {
michael@0 353 LOG(("Trying to fall back on internal ntlm auth.\n"));
michael@0 354 module = do_CreateInstance(NS_AUTH_MODULE_CONTRACTID_PREFIX "ntlm");
michael@0 355 }
michael@0 356
michael@0 357 mUseNative = false;
michael@0 358
michael@0 359 // Prompt user for domain, username, and password.
michael@0 360 *identityInvalid = true;
michael@0 361 }
michael@0 362
michael@0 363 // If this fails, then it means that we cannot do NTLM auth.
michael@0 364 if (!module) {
michael@0 365 LOG(("No ntlm auth modules available.\n"));
michael@0 366 return NS_ERROR_UNEXPECTED;
michael@0 367 }
michael@0 368
michael@0 369 // A non-null continuation state implies that we failed to authenticate.
michael@0 370 // Blow away the old authentication state, and use the new one.
michael@0 371 module.swap(*continuationState);
michael@0 372 }
michael@0 373 return NS_OK;
michael@0 374 }
michael@0 375
michael@0 376 NS_IMETHODIMP
michael@0 377 nsHttpNTLMAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
michael@0 378 const char *challenge,
michael@0 379 bool isProxyAuth,
michael@0 380 const char16_t *domain,
michael@0 381 const char16_t *user,
michael@0 382 const char16_t *pass,
michael@0 383 nsISupports **sessionState,
michael@0 384 nsISupports **continuationState,
michael@0 385 uint32_t *aFlags,
michael@0 386 char **creds)
michael@0 387
michael@0 388 {
michael@0 389 LOG(("nsHttpNTLMAuth::GenerateCredentials\n"));
michael@0 390
michael@0 391 *creds = nullptr;
michael@0 392 *aFlags = 0;
michael@0 393
michael@0 394 // if user or password is empty, ChallengeReceived returned
michael@0 395 // identityInvalid = false, that means we are using default user
michael@0 396 // credentials; see nsAuthSSPI::Init method for explanation of this
michael@0 397 // condition
michael@0 398 if (!user || !pass)
michael@0 399 *aFlags = USING_INTERNAL_IDENTITY;
michael@0 400
michael@0 401 nsresult rv;
michael@0 402 nsCOMPtr<nsIAuthModule> module = do_QueryInterface(*continuationState, &rv);
michael@0 403 NS_ENSURE_SUCCESS(rv, rv);
michael@0 404
michael@0 405 void *inBuf, *outBuf;
michael@0 406 uint32_t inBufLen, outBufLen;
michael@0 407
michael@0 408 // initial challenge
michael@0 409 if (PL_strcasecmp(challenge, "NTLM") == 0) {
michael@0 410 // NTLM service name format is 'HTTP@host' for both http and https
michael@0 411 nsCOMPtr<nsIURI> uri;
michael@0 412 rv = authChannel->GetURI(getter_AddRefs(uri));
michael@0 413 if (NS_FAILED(rv))
michael@0 414 return rv;
michael@0 415 nsAutoCString serviceName, host;
michael@0 416 rv = uri->GetAsciiHost(host);
michael@0 417 if (NS_FAILED(rv))
michael@0 418 return rv;
michael@0 419 serviceName.AppendLiteral("HTTP@");
michael@0 420 serviceName.Append(host);
michael@0 421 // initialize auth module
michael@0 422 uint32_t reqFlags = nsIAuthModule::REQ_DEFAULT;
michael@0 423 if (isProxyAuth)
michael@0 424 reqFlags |= nsIAuthModule::REQ_PROXY_AUTH;
michael@0 425
michael@0 426 rv = module->Init(serviceName.get(), reqFlags, domain, user, pass);
michael@0 427 if (NS_FAILED(rv))
michael@0 428 return rv;
michael@0 429
michael@0 430 // This update enables updated Windows machines (Win7 or patched previous
michael@0 431 // versions) and Linux machines running Samba (updated for Channel
michael@0 432 // Binding), to perform Channel Binding when authenticating using NTLMv2
michael@0 433 // and an outer secure channel.
michael@0 434 //
michael@0 435 // Currently only implemented for Windows, linux support will be landing in
michael@0 436 // a separate patch, update this #ifdef accordingly then.
michael@0 437 #if defined (XP_WIN) /* || defined (LINUX) */
michael@0 438 // We should retrieve the server certificate and compute the CBT,
michael@0 439 // but only when we are using the native NTLM implementation and
michael@0 440 // not the internal one.
michael@0 441 // It is a valid case not having the security info object. This
michael@0 442 // occures when we connect an https site through an ntlm proxy.
michael@0 443 // After the ssl tunnel has been created, we get here the second
michael@0 444 // time and now generate the CBT from now valid security info.
michael@0 445 nsCOMPtr<nsIChannel> channel = do_QueryInterface(authChannel, &rv);
michael@0 446 if (NS_FAILED(rv))
michael@0 447 return rv;
michael@0 448
michael@0 449 nsCOMPtr<nsISupports> security;
michael@0 450 rv = channel->GetSecurityInfo(getter_AddRefs(security));
michael@0 451 if (NS_FAILED(rv))
michael@0 452 return rv;
michael@0 453
michael@0 454 nsCOMPtr<nsISSLStatusProvider> statusProvider =
michael@0 455 do_QueryInterface(security);
michael@0 456
michael@0 457 if (mUseNative && statusProvider) {
michael@0 458 nsCOMPtr<nsISSLStatus> status;
michael@0 459 rv = statusProvider->GetSSLStatus(getter_AddRefs(status));
michael@0 460 if (NS_FAILED(rv))
michael@0 461 return rv;
michael@0 462
michael@0 463 nsCOMPtr<nsIX509Cert> cert;
michael@0 464 rv = status->GetServerCert(getter_AddRefs(cert));
michael@0 465 if (NS_FAILED(rv))
michael@0 466 return rv;
michael@0 467
michael@0 468 uint32_t length;
michael@0 469 uint8_t* certArray;
michael@0 470 cert->GetRawDER(&length, &certArray);
michael@0 471
michael@0 472 // If there is a server certificate, we pass it along the
michael@0 473 // first time we call GetNextToken().
michael@0 474 inBufLen = length;
michael@0 475 inBuf = certArray;
michael@0 476 } else {
michael@0 477 // If there is no server certificate, we don't pass anything.
michael@0 478 inBufLen = 0;
michael@0 479 inBuf = nullptr;
michael@0 480 }
michael@0 481 #else // Extended protection update is just for Linux and Windows machines.
michael@0 482 inBufLen = 0;
michael@0 483 inBuf = nullptr;
michael@0 484 #endif
michael@0 485 }
michael@0 486 else {
michael@0 487 // decode challenge; skip past "NTLM " to the start of the base64
michael@0 488 // encoded data.
michael@0 489 int len = strlen(challenge);
michael@0 490 if (len < 6)
michael@0 491 return NS_ERROR_UNEXPECTED; // bogus challenge
michael@0 492 challenge += 5;
michael@0 493 len -= 5;
michael@0 494
michael@0 495 // strip off any padding (see bug 230351)
michael@0 496 while (challenge[len - 1] == '=')
michael@0 497 len--;
michael@0 498
michael@0 499 // decode into the input secbuffer
michael@0 500 inBufLen = (len * 3)/4; // sufficient size (see plbase64.h)
michael@0 501 inBuf = nsMemory::Alloc(inBufLen);
michael@0 502 if (!inBuf)
michael@0 503 return NS_ERROR_OUT_OF_MEMORY;
michael@0 504
michael@0 505 if (PL_Base64Decode(challenge, len, (char *) inBuf) == nullptr) {
michael@0 506 nsMemory::Free(inBuf);
michael@0 507 return NS_ERROR_UNEXPECTED; // improper base64 encoding
michael@0 508 }
michael@0 509 }
michael@0 510
michael@0 511 rv = module->GetNextToken(inBuf, inBufLen, &outBuf, &outBufLen);
michael@0 512 if (NS_SUCCEEDED(rv)) {
michael@0 513 // base64 encode data in output buffer and prepend "NTLM "
michael@0 514 int credsLen = 5 + ((outBufLen + 2)/3)*4;
michael@0 515 *creds = (char *) nsMemory::Alloc(credsLen + 1);
michael@0 516 if (!*creds)
michael@0 517 rv = NS_ERROR_OUT_OF_MEMORY;
michael@0 518 else {
michael@0 519 memcpy(*creds, "NTLM ", 5);
michael@0 520 PL_Base64Encode((char *) outBuf, outBufLen, *creds + 5);
michael@0 521 (*creds)[credsLen] = '\0'; // null terminate
michael@0 522 }
michael@0 523 // OK, we are done with |outBuf|
michael@0 524 nsMemory::Free(outBuf);
michael@0 525 }
michael@0 526
michael@0 527 if (inBuf)
michael@0 528 nsMemory::Free(inBuf);
michael@0 529
michael@0 530 return rv;
michael@0 531 }
michael@0 532
michael@0 533 NS_IMETHODIMP
michael@0 534 nsHttpNTLMAuth::GetAuthFlags(uint32_t *flags)
michael@0 535 {
michael@0 536 *flags = CONNECTION_BASED | IDENTITY_INCLUDES_DOMAIN | IDENTITY_ENCRYPTED;
michael@0 537 return NS_OK;
michael@0 538 }
michael@0 539
michael@0 540 } // namespace mozilla::net
michael@0 541 } // namespace mozilla

mercurial