netwerk/protocol/http/nsHttpNTLMAuth.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/protocol/http/nsHttpNTLMAuth.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,541 @@
     1.4 +/* vim:set ts=4 sw=4 sts=4 et ci: */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +// HttpLog.h should generally be included first
    1.10 +#include "HttpLog.h"
    1.11 +
    1.12 +#include "nsHttpNTLMAuth.h"
    1.13 +#include "nsIAuthModule.h"
    1.14 +#include "nsCOMPtr.h"
    1.15 +#include "plbase64.h"
    1.16 +#include "prnetdb.h"
    1.17 +
    1.18 +//-----------------------------------------------------------------------------
    1.19 +
    1.20 +#include "nsIPrefBranch.h"
    1.21 +#include "nsIPrefService.h"
    1.22 +#include "nsIHttpAuthenticableChannel.h"
    1.23 +#include "nsIURI.h"
    1.24 +#ifdef XP_WIN
    1.25 +#include "nsIX509Cert.h"
    1.26 +#include "nsISSLStatus.h"
    1.27 +#include "nsISSLStatusProvider.h"
    1.28 +#endif
    1.29 +#include "mozilla/Attributes.h"
    1.30 +#include "nsThreadUtils.h"
    1.31 +
    1.32 +namespace mozilla {
    1.33 +namespace net {
    1.34 +
    1.35 +static const char kAllowProxies[] = "network.automatic-ntlm-auth.allow-proxies";
    1.36 +static const char kAllowNonFqdn[] = "network.automatic-ntlm-auth.allow-non-fqdn";
    1.37 +static const char kTrustedURIs[]  = "network.automatic-ntlm-auth.trusted-uris";
    1.38 +static const char kForceGeneric[] = "network.auth.force-generic-ntlm";
    1.39 +static const char kAllowGenericHTTP[] = "network.negotiate-auth.allow-insecure-ntlm-v1";
    1.40 +static const char kAllowGenericHTTPS[] = "network.negotiate-auth.allow-insecure-ntlm-v1-https";
    1.41 +
    1.42 +// XXX MatchesBaseURI and TestPref are duplicated in nsHttpNegotiateAuth.cpp,
    1.43 +// but since that file lives in a separate library we cannot directly share it.
    1.44 +// bug 236865 addresses this problem.
    1.45 +
    1.46 +static bool
    1.47 +MatchesBaseURI(const nsCSubstring &matchScheme,
    1.48 +               const nsCSubstring &matchHost,
    1.49 +               int32_t             matchPort,
    1.50 +               const char         *baseStart,
    1.51 +               const char         *baseEnd)
    1.52 +{
    1.53 +    // check if scheme://host:port matches baseURI
    1.54 +
    1.55 +    // parse the base URI
    1.56 +    const char *hostStart, *schemeEnd = strstr(baseStart, "://");
    1.57 +    if (schemeEnd) {
    1.58 +        // the given scheme must match the parsed scheme exactly
    1.59 +        if (!matchScheme.Equals(Substring(baseStart, schemeEnd)))
    1.60 +            return false;
    1.61 +        hostStart = schemeEnd + 3;
    1.62 +    }
    1.63 +    else
    1.64 +        hostStart = baseStart;
    1.65 +
    1.66 +    // XXX this does not work for IPv6-literals
    1.67 +    const char *hostEnd = strchr(hostStart, ':');
    1.68 +    if (hostEnd && hostEnd < baseEnd) {
    1.69 +        // the given port must match the parsed port exactly
    1.70 +        int port = atoi(hostEnd + 1);
    1.71 +        if (matchPort != (int32_t) port)
    1.72 +            return false;
    1.73 +    }
    1.74 +    else
    1.75 +        hostEnd = baseEnd;
    1.76 +
    1.77 +
    1.78 +    // if we didn't parse out a host, then assume we got a match.
    1.79 +    if (hostStart == hostEnd)
    1.80 +        return true;
    1.81 +
    1.82 +    uint32_t hostLen = hostEnd - hostStart;
    1.83 +
    1.84 +    // matchHost must either equal host or be a subdomain of host
    1.85 +    if (matchHost.Length() < hostLen)
    1.86 +        return false;
    1.87 +
    1.88 +    const char *end = matchHost.EndReading();
    1.89 +    if (PL_strncasecmp(end - hostLen, hostStart, hostLen) == 0) {
    1.90 +        // if matchHost ends with host from the base URI, then make sure it is
    1.91 +        // either an exact match, or prefixed with a dot.  we don't want
    1.92 +        // "foobar.com" to match "bar.com"
    1.93 +        if (matchHost.Length() == hostLen ||
    1.94 +            *(end - hostLen) == '.' ||
    1.95 +            *(end - hostLen - 1) == '.')
    1.96 +            return true;
    1.97 +    }
    1.98 +
    1.99 +    return false;
   1.100 +}
   1.101 +
   1.102 +static bool
   1.103 +IsNonFqdn(nsIURI *uri)
   1.104 +{
   1.105 +    nsAutoCString host;
   1.106 +    PRNetAddr addr;
   1.107 +
   1.108 +    if (NS_FAILED(uri->GetAsciiHost(host)))
   1.109 +        return false;
   1.110 +
   1.111 +    // return true if host does not contain a dot and is not an ip address
   1.112 +    return !host.IsEmpty() && host.FindChar('.') == kNotFound &&
   1.113 +           PR_StringToNetAddr(host.BeginReading(), &addr) != PR_SUCCESS;
   1.114 +}
   1.115 +
   1.116 +static bool
   1.117 +TestPref(nsIURI *uri, const char *pref)
   1.118 +{
   1.119 +    nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   1.120 +    if (!prefs)
   1.121 +        return false;
   1.122 +
   1.123 +    nsAutoCString scheme, host;
   1.124 +    int32_t port;
   1.125 +
   1.126 +    if (NS_FAILED(uri->GetScheme(scheme)))
   1.127 +        return false;
   1.128 +    if (NS_FAILED(uri->GetAsciiHost(host)))
   1.129 +        return false;
   1.130 +    if (NS_FAILED(uri->GetPort(&port)))
   1.131 +        return false;
   1.132 +
   1.133 +    char *hostList;
   1.134 +    if (NS_FAILED(prefs->GetCharPref(pref, &hostList)) || !hostList)
   1.135 +        return false;
   1.136 +
   1.137 +    // pseudo-BNF
   1.138 +    // ----------
   1.139 +    //
   1.140 +    // url-list       base-url ( base-url "," LWS )*
   1.141 +    // base-url       ( scheme-part | host-part | scheme-part host-part )
   1.142 +    // scheme-part    scheme "://"
   1.143 +    // host-part      host [":" port]
   1.144 +    //
   1.145 +    // for example:
   1.146 +    //   "https://, http://office.foo.com"
   1.147 +    //
   1.148 +
   1.149 +    char *start = hostList, *end;
   1.150 +    for (;;) {
   1.151 +        // skip past any whitespace
   1.152 +        while (*start == ' ' || *start == '\t')
   1.153 +            ++start;
   1.154 +        end = strchr(start, ',');
   1.155 +        if (!end)
   1.156 +            end = start + strlen(start);
   1.157 +        if (start == end)
   1.158 +            break;
   1.159 +        if (MatchesBaseURI(scheme, host, port, start, end))
   1.160 +            return true;
   1.161 +        if (*end == '\0')
   1.162 +            break;
   1.163 +        start = end + 1;
   1.164 +    }
   1.165 +
   1.166 +    nsMemory::Free(hostList);
   1.167 +    return false;
   1.168 +}
   1.169 +
   1.170 +// Check to see if we should use our generic (internal) NTLM auth module.
   1.171 +static bool
   1.172 +ForceGenericNTLM()
   1.173 +{
   1.174 +    nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   1.175 +    if (!prefs)
   1.176 +        return false;
   1.177 +    bool flag = false;
   1.178 +
   1.179 +    if (NS_FAILED(prefs->GetBoolPref(kForceGeneric, &flag)))
   1.180 +        flag = false;
   1.181 +
   1.182 +    LOG(("Force use of generic ntlm auth module: %d\n", flag));
   1.183 +    return flag;
   1.184 +}
   1.185 +
   1.186 +// Check to see if we should use our generic (internal) NTLM auth module.
   1.187 +static bool
   1.188 +AllowGenericNTLM()
   1.189 +{
   1.190 +    MOZ_ASSERT(NS_IsMainThread());
   1.191 +
   1.192 +    nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   1.193 +    if (!prefs)
   1.194 +        return false;
   1.195 +
   1.196 +    bool flag = false;
   1.197 +    if (NS_FAILED(prefs->GetBoolPref(kAllowGenericHTTP, &flag)))
   1.198 +        flag = false;
   1.199 +
   1.200 +    LOG(("Allow use of generic ntlm auth module: %d\n", flag));
   1.201 +    return flag;
   1.202 +}
   1.203 +
   1.204 +// Check to see if we should use our generic (internal) NTLM auth module.
   1.205 +static bool
   1.206 +AllowGenericNTLMforHTTPS(nsIHttpAuthenticableChannel *channel)
   1.207 +{
   1.208 +    bool isSSL = false;
   1.209 +    channel->GetIsSSL(&isSSL);
   1.210 +    if (!isSSL)
   1.211 +        return false;
   1.212 +
   1.213 +    MOZ_ASSERT(NS_IsMainThread());
   1.214 +
   1.215 +    nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   1.216 +    if (!prefs)
   1.217 +        return false;
   1.218 +
   1.219 +    bool flag = false;
   1.220 +    if (NS_FAILED(prefs->GetBoolPref(kAllowGenericHTTPS, &flag)))
   1.221 +        flag = false;
   1.222 +
   1.223 +    LOG(("Allow use of generic ntlm auth module for only https: %d\n", flag));
   1.224 +    return flag;
   1.225 +}
   1.226 +
   1.227 +// Check to see if we should use default credentials for this host or proxy.
   1.228 +static bool
   1.229 +CanUseDefaultCredentials(nsIHttpAuthenticableChannel *channel,
   1.230 +                         bool isProxyAuth)
   1.231 +{
   1.232 +    nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   1.233 +    if (!prefs)
   1.234 +        return false;
   1.235 +
   1.236 +    if (isProxyAuth) {
   1.237 +        bool val;
   1.238 +        if (NS_FAILED(prefs->GetBoolPref(kAllowProxies, &val)))
   1.239 +            val = false;
   1.240 +        LOG(("Default credentials allowed for proxy: %d\n", val));
   1.241 +        return val;
   1.242 +    }
   1.243 +
   1.244 +    nsCOMPtr<nsIURI> uri;
   1.245 +    channel->GetURI(getter_AddRefs(uri));
   1.246 +
   1.247 +    bool allowNonFqdn;
   1.248 +    if (NS_FAILED(prefs->GetBoolPref(kAllowNonFqdn, &allowNonFqdn)))
   1.249 +        allowNonFqdn = false;
   1.250 +    if (allowNonFqdn && uri && IsNonFqdn(uri)) {
   1.251 +        LOG(("Host is non-fqdn, default credentials are allowed\n"));
   1.252 +        return true;
   1.253 +    }
   1.254 +
   1.255 +    bool isTrustedHost = (uri && TestPref(uri, kTrustedURIs));
   1.256 +    LOG(("Default credentials allowed for host: %d\n", isTrustedHost));
   1.257 +    return isTrustedHost;
   1.258 +}
   1.259 +
   1.260 +// Dummy class for session state object.  This class doesn't hold any data.
   1.261 +// Instead we use its existence as a flag.  See ChallengeReceived.
   1.262 +class nsNTLMSessionState MOZ_FINAL : public nsISupports
   1.263 +{
   1.264 +public:
   1.265 +    NS_DECL_ISUPPORTS
   1.266 +};
   1.267 +NS_IMPL_ISUPPORTS0(nsNTLMSessionState)
   1.268 +
   1.269 +//-----------------------------------------------------------------------------
   1.270 +
   1.271 +NS_IMPL_ISUPPORTS(nsHttpNTLMAuth, nsIHttpAuthenticator)
   1.272 +
   1.273 +NS_IMETHODIMP
   1.274 +nsHttpNTLMAuth::ChallengeReceived(nsIHttpAuthenticableChannel *channel,
   1.275 +                                  const char     *challenge,
   1.276 +                                  bool            isProxyAuth,
   1.277 +                                  nsISupports   **sessionState,
   1.278 +                                  nsISupports   **continuationState,
   1.279 +                                  bool           *identityInvalid)
   1.280 +{
   1.281 +    LOG(("nsHttpNTLMAuth::ChallengeReceived [ss=%p cs=%p]\n",
   1.282 +         *sessionState, *continuationState));
   1.283 +
   1.284 +    // Use the native NTLM if available
   1.285 +    mUseNative = true;
   1.286 +
   1.287 +    // NOTE: we don't define any session state, but we do use the pointer.
   1.288 +
   1.289 +    *identityInvalid = false;
   1.290 +
   1.291 +    /* Always fail Negotiate auth for Tor Browser. We don't need it. */
   1.292 +    return NS_ERROR_ABORT;
   1.293 +
   1.294 +    // Start a new auth sequence if the challenge is exactly "NTLM".
   1.295 +    // If native NTLM auth apis are available and enabled through prefs,
   1.296 +    // try to use them.
   1.297 +    if (PL_strcasecmp(challenge, "NTLM") == 0) {
   1.298 +        nsCOMPtr<nsISupports> module;
   1.299 +
   1.300 +        // Check to see if we should default to our generic NTLM auth module
   1.301 +        // through UseGenericNTLM. (We use native auth by default if the
   1.302 +        // system provides it.) If *sessionState is non-null, we failed to
   1.303 +        // instantiate a native NTLM module the last time, so skip trying again.
   1.304 +        bool forceGeneric = ForceGenericNTLM();
   1.305 +        if (!forceGeneric && !*sessionState) {
   1.306 +            // Check for approved default credentials hosts and proxies. If
   1.307 +            // *continuationState is non-null, the last authentication attempt
   1.308 +            // failed so skip default credential use.
   1.309 +            if (!*continuationState && CanUseDefaultCredentials(channel, isProxyAuth)) {
   1.310 +                // Try logging in with the user's default credentials. If
   1.311 +                // successful, |identityInvalid| is false, which will trigger
   1.312 +                // a default credentials attempt once we return.
   1.313 +                module = do_CreateInstance(NS_AUTH_MODULE_CONTRACTID_PREFIX "sys-ntlm");
   1.314 +            }
   1.315 +#ifdef XP_WIN
   1.316 +            else {
   1.317 +                // Try to use native NTLM and prompt the user for their domain,
   1.318 +                // username, and password. (only supported by windows nsAuthSSPI module.)
   1.319 +                // Note, for servers that use LMv1 a weak hash of the user's password
   1.320 +                // will be sent. We rely on windows internal apis to decide whether
   1.321 +                // we should support this older, less secure version of the protocol.
   1.322 +                module = do_CreateInstance(NS_AUTH_MODULE_CONTRACTID_PREFIX "sys-ntlm");
   1.323 +                *identityInvalid = true;
   1.324 +            }
   1.325 +#endif // XP_WIN
   1.326 +#ifdef PR_LOGGING
   1.327 +            if (!module)
   1.328 +                LOG(("Native sys-ntlm auth module not found.\n"));
   1.329 +#endif
   1.330 +        }
   1.331 +
   1.332 +#ifdef XP_WIN
   1.333 +        // On windows, never fall back unless the user has specifically requested so.
   1.334 +        if (!forceGeneric && !module)
   1.335 +            return NS_ERROR_UNEXPECTED;
   1.336 +#endif
   1.337 +
   1.338 +        // If no native support was available. Fall back on our internal NTLM implementation.
   1.339 +        if (!module) {
   1.340 +            if (!*sessionState) {
   1.341 +                // Remember the fact that we cannot use the "sys-ntlm" module,
   1.342 +                // so we don't ever bother trying again for this auth domain.
   1.343 +                *sessionState = new nsNTLMSessionState();
   1.344 +                if (!*sessionState)
   1.345 +                    return NS_ERROR_OUT_OF_MEMORY;
   1.346 +                NS_ADDREF(*sessionState);
   1.347 +            }
   1.348 +
   1.349 +            // Use our internal NTLM implementation. Note, this is less secure,
   1.350 +            // see bug 520607 for details.
   1.351 +
   1.352 +            // For now with default preference settings (i.e. allow-insecure-ntlm-v1-https = true
   1.353 +            // and allow-insecure-ntlm-v1 = false) we don't allow authentication to any proxy,
   1.354 +            // either http or https.  This will be fixed in a followup bug.
   1.355 +            if (AllowGenericNTLM() || (!isProxyAuth && AllowGenericNTLMforHTTPS(channel))) {
   1.356 +                LOG(("Trying to fall back on internal ntlm auth.\n"));
   1.357 +                module = do_CreateInstance(NS_AUTH_MODULE_CONTRACTID_PREFIX "ntlm");
   1.358 +            }
   1.359 +	
   1.360 +            mUseNative = false;
   1.361 +
   1.362 +            // Prompt user for domain, username, and password.
   1.363 +            *identityInvalid = true;
   1.364 +        }
   1.365 +
   1.366 +        // If this fails, then it means that we cannot do NTLM auth.
   1.367 +        if (!module) {
   1.368 +            LOG(("No ntlm auth modules available.\n"));
   1.369 +            return NS_ERROR_UNEXPECTED;
   1.370 +        }
   1.371 +
   1.372 +        // A non-null continuation state implies that we failed to authenticate.
   1.373 +        // Blow away the old authentication state, and use the new one.
   1.374 +        module.swap(*continuationState);
   1.375 +    }
   1.376 +    return NS_OK;
   1.377 +}
   1.378 +
   1.379 +NS_IMETHODIMP
   1.380 +nsHttpNTLMAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
   1.381 +                                    const char      *challenge,
   1.382 +                                    bool             isProxyAuth,
   1.383 +                                    const char16_t *domain,
   1.384 +                                    const char16_t *user,
   1.385 +                                    const char16_t *pass,
   1.386 +                                    nsISupports    **sessionState,
   1.387 +                                    nsISupports    **continuationState,
   1.388 +                                    uint32_t       *aFlags,
   1.389 +                                    char           **creds)
   1.390 +
   1.391 +{
   1.392 +    LOG(("nsHttpNTLMAuth::GenerateCredentials\n"));
   1.393 +
   1.394 +    *creds = nullptr;
   1.395 +    *aFlags = 0;
   1.396 +
   1.397 +    // if user or password is empty, ChallengeReceived returned
   1.398 +    // identityInvalid = false, that means we are using default user
   1.399 +    // credentials; see  nsAuthSSPI::Init method for explanation of this
   1.400 +    // condition
   1.401 +    if (!user || !pass)
   1.402 +        *aFlags = USING_INTERNAL_IDENTITY;
   1.403 +
   1.404 +    nsresult rv;
   1.405 +    nsCOMPtr<nsIAuthModule> module = do_QueryInterface(*continuationState, &rv);
   1.406 +    NS_ENSURE_SUCCESS(rv, rv);
   1.407 +
   1.408 +    void *inBuf, *outBuf;
   1.409 +    uint32_t inBufLen, outBufLen;
   1.410 +
   1.411 +    // initial challenge
   1.412 +    if (PL_strcasecmp(challenge, "NTLM") == 0) {
   1.413 +        // NTLM service name format is 'HTTP@host' for both http and https
   1.414 +        nsCOMPtr<nsIURI> uri;
   1.415 +        rv = authChannel->GetURI(getter_AddRefs(uri));
   1.416 +        if (NS_FAILED(rv))
   1.417 +            return rv;
   1.418 +        nsAutoCString serviceName, host;
   1.419 +        rv = uri->GetAsciiHost(host);
   1.420 +        if (NS_FAILED(rv))
   1.421 +            return rv;
   1.422 +        serviceName.AppendLiteral("HTTP@");
   1.423 +        serviceName.Append(host);
   1.424 +        // initialize auth module
   1.425 +        uint32_t reqFlags = nsIAuthModule::REQ_DEFAULT;
   1.426 +        if (isProxyAuth)
   1.427 +            reqFlags |= nsIAuthModule::REQ_PROXY_AUTH;
   1.428 +
   1.429 +        rv = module->Init(serviceName.get(), reqFlags, domain, user, pass);
   1.430 +        if (NS_FAILED(rv))
   1.431 +            return rv;
   1.432 +
   1.433 +// This update enables updated Windows machines (Win7 or patched previous
   1.434 +// versions) and Linux machines running Samba (updated for Channel
   1.435 +// Binding), to perform Channel Binding when authenticating using NTLMv2
   1.436 +// and an outer secure channel.
   1.437 +//
   1.438 +// Currently only implemented for Windows, linux support will be landing in
   1.439 +// a separate patch, update this #ifdef accordingly then.
   1.440 +#if defined (XP_WIN) /* || defined (LINUX) */
   1.441 +        // We should retrieve the server certificate and compute the CBT,
   1.442 +        // but only when we are using the native NTLM implementation and
   1.443 +        // not the internal one.
   1.444 +        // It is a valid case not having the security info object.  This
   1.445 +        // occures when we connect an https site through an ntlm proxy.
   1.446 +        // After the ssl tunnel has been created, we get here the second
   1.447 +        // time and now generate the CBT from now valid security info.
   1.448 +        nsCOMPtr<nsIChannel> channel = do_QueryInterface(authChannel, &rv);
   1.449 +        if (NS_FAILED(rv))
   1.450 +            return rv;
   1.451 +
   1.452 +        nsCOMPtr<nsISupports> security;
   1.453 +        rv = channel->GetSecurityInfo(getter_AddRefs(security));
   1.454 +        if (NS_FAILED(rv))
   1.455 +            return rv;
   1.456 +
   1.457 +        nsCOMPtr<nsISSLStatusProvider> statusProvider =
   1.458 +            do_QueryInterface(security);
   1.459 +
   1.460 +        if (mUseNative && statusProvider) {
   1.461 +            nsCOMPtr<nsISSLStatus> status;
   1.462 +            rv = statusProvider->GetSSLStatus(getter_AddRefs(status));
   1.463 +            if (NS_FAILED(rv))
   1.464 +                return rv;
   1.465 +
   1.466 +            nsCOMPtr<nsIX509Cert> cert;
   1.467 +            rv = status->GetServerCert(getter_AddRefs(cert));
   1.468 +            if (NS_FAILED(rv))
   1.469 +                return rv;
   1.470 +
   1.471 +            uint32_t length;
   1.472 +            uint8_t* certArray;
   1.473 +            cert->GetRawDER(&length, &certArray);						
   1.474 +			
   1.475 +            // If there is a server certificate, we pass it along the
   1.476 +            // first time we call GetNextToken().
   1.477 +            inBufLen = length;
   1.478 +            inBuf = certArray;
   1.479 +        } else {
   1.480 +            // If there is no server certificate, we don't pass anything.
   1.481 +            inBufLen = 0;
   1.482 +            inBuf = nullptr;
   1.483 +        }
   1.484 +#else // Extended protection update is just for Linux and Windows machines.
   1.485 +        inBufLen = 0;
   1.486 +        inBuf = nullptr;
   1.487 +#endif
   1.488 +    }
   1.489 +    else {
   1.490 +        // decode challenge; skip past "NTLM " to the start of the base64
   1.491 +        // encoded data.
   1.492 +        int len = strlen(challenge);
   1.493 +        if (len < 6)
   1.494 +            return NS_ERROR_UNEXPECTED; // bogus challenge
   1.495 +        challenge += 5;
   1.496 +        len -= 5;
   1.497 +
   1.498 +        // strip off any padding (see bug 230351)
   1.499 +        while (challenge[len - 1] == '=')
   1.500 +          len--;
   1.501 +
   1.502 +        // decode into the input secbuffer
   1.503 +        inBufLen = (len * 3)/4;      // sufficient size (see plbase64.h)
   1.504 +        inBuf = nsMemory::Alloc(inBufLen);
   1.505 +        if (!inBuf)
   1.506 +            return NS_ERROR_OUT_OF_MEMORY;
   1.507 +
   1.508 +        if (PL_Base64Decode(challenge, len, (char *) inBuf) == nullptr) {
   1.509 +            nsMemory::Free(inBuf);
   1.510 +            return NS_ERROR_UNEXPECTED; // improper base64 encoding
   1.511 +        }
   1.512 +    }
   1.513 +
   1.514 +    rv = module->GetNextToken(inBuf, inBufLen, &outBuf, &outBufLen);
   1.515 +    if (NS_SUCCEEDED(rv)) {
   1.516 +        // base64 encode data in output buffer and prepend "NTLM "
   1.517 +        int credsLen = 5 + ((outBufLen + 2)/3)*4;
   1.518 +        *creds = (char *) nsMemory::Alloc(credsLen + 1);
   1.519 +        if (!*creds)
   1.520 +            rv = NS_ERROR_OUT_OF_MEMORY;
   1.521 +        else {
   1.522 +            memcpy(*creds, "NTLM ", 5);
   1.523 +            PL_Base64Encode((char *) outBuf, outBufLen, *creds + 5);
   1.524 +            (*creds)[credsLen] = '\0'; // null terminate
   1.525 +        }
   1.526 +        // OK, we are done with |outBuf|
   1.527 +        nsMemory::Free(outBuf);
   1.528 +    }
   1.529 +
   1.530 +    if (inBuf)
   1.531 +        nsMemory::Free(inBuf);
   1.532 +
   1.533 +    return rv;
   1.534 +}
   1.535 +
   1.536 +NS_IMETHODIMP
   1.537 +nsHttpNTLMAuth::GetAuthFlags(uint32_t *flags)
   1.538 +{
   1.539 +    *flags = CONNECTION_BASED | IDENTITY_INCLUDES_DOMAIN | IDENTITY_ENCRYPTED;
   1.540 +    return NS_OK;
   1.541 +}
   1.542 +
   1.543 +} // namespace mozilla::net
   1.544 +} // namespace mozilla

mercurial