LCOV - code coverage report
Current view: top level - netwerk/protocol/http - nsHttpNTLMAuth.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 131 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 15 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* vim:set ts=4 sw=4 sts=4 et ci: */
       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             : // HttpLog.h should generally be included first
       7             : #include "HttpLog.h"
       8             : 
       9             : #include "nsHttpNTLMAuth.h"
      10             : #include "nsIAuthModule.h"
      11             : #include "nsCOMPtr.h"
      12             : #include "nsServiceManagerUtils.h"
      13             : #include "plbase64.h"
      14             : #include "plstr.h"
      15             : #include "prnetdb.h"
      16             : 
      17             : //-----------------------------------------------------------------------------
      18             : 
      19             : #include "nsIPrefBranch.h"
      20             : #include "nsIPrefService.h"
      21             : #include "nsIHttpAuthenticableChannel.h"
      22             : #include "nsIURI.h"
      23             : #ifdef XP_WIN
      24             : #include "nsIChannel.h"
      25             : #include "nsIX509Cert.h"
      26             : #include "nsISSLStatus.h"
      27             : #include "nsISSLStatusProvider.h"
      28             : #endif
      29             : #include "mozilla/Attributes.h"
      30             : #include "mozilla/Base64.h"
      31             : #include "mozilla/CheckedInt.h"
      32             : #include "mozilla/Tokenizer.h"
      33             : #include "mozilla/UniquePtr.h"
      34             : #include "mozilla/Unused.h"
      35             : #include "nsNetUtil.h"
      36             : #include "nsIChannel.h"
      37             : #include "nsUnicharUtils.h"
      38             : #include "mozilla/net/HttpAuthUtils.h"
      39             : 
      40             : namespace mozilla {
      41             : namespace net {
      42             : 
      43             : static const char kAllowProxies[] = "network.automatic-ntlm-auth.allow-proxies";
      44             : static const char kAllowNonFqdn[] = "network.automatic-ntlm-auth.allow-non-fqdn";
      45             : static const char kTrustedURIs[]  = "network.automatic-ntlm-auth.trusted-uris";
      46             : static const char kForceGeneric[] = "network.auth.force-generic-ntlm";
      47             : static const char kSSOinPBmode[] = "network.auth.private-browsing-sso";
      48             : 
      49             : static bool
      50           0 : IsNonFqdn(nsIURI *uri)
      51             : {
      52           0 :     nsAutoCString host;
      53             :     PRNetAddr addr;
      54             : 
      55           0 :     if (NS_FAILED(uri->GetAsciiHost(host)))
      56           0 :         return false;
      57             : 
      58             :     // return true if host does not contain a dot and is not an ip address
      59           0 :     return !host.IsEmpty() && !host.Contains('.') &&
      60           0 :            PR_StringToNetAddr(host.BeginReading(), &addr) != PR_SUCCESS;
      61             : }
      62             : 
      63             : // Check to see if we should use our generic (internal) NTLM auth module.
      64             : static bool
      65           0 : ForceGenericNTLM()
      66             : {
      67           0 :     nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
      68           0 :     if (!prefs)
      69           0 :         return false;
      70           0 :     bool flag = false;
      71             : 
      72           0 :     if (NS_FAILED(prefs->GetBoolPref(kForceGeneric, &flag)))
      73           0 :         flag = false;
      74             : 
      75           0 :     LOG(("Force use of generic ntlm auth module: %d\n", flag));
      76           0 :     return flag;
      77             : }
      78             : 
      79             : // Check to see if we should use default credentials for this host or proxy.
      80             : static bool
      81           0 : CanUseDefaultCredentials(nsIHttpAuthenticableChannel *channel,
      82             :                          bool isProxyAuth)
      83             : {
      84           0 :     nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
      85           0 :     if (!prefs) {
      86           0 :         return false;
      87             :     }
      88             : 
      89             :     // Proxy should go all the time, it's not considered a privacy leak
      90             :     // to send default credentials to a proxy.
      91           0 :     if (isProxyAuth) {
      92             :         bool val;
      93           0 :         if (NS_FAILED(prefs->GetBoolPref(kAllowProxies, &val)))
      94           0 :             val = false;
      95           0 :         LOG(("Default credentials allowed for proxy: %d\n", val));
      96           0 :         return val;
      97             :     }
      98             : 
      99             :     // Prevent using default credentials for authentication when we are in the
     100             :     // private browsing mode (but not in "never remember history" mode) and when
     101             :     // not explicitely allowed.  Otherwise, it would cause a privacy data leak.
     102           0 :     nsCOMPtr<nsIChannel> bareChannel = do_QueryInterface(channel);
     103           0 :     MOZ_ASSERT(bareChannel);
     104             : 
     105           0 :     if (NS_UsePrivateBrowsing(bareChannel)) {
     106             :         bool ssoInPb;
     107           0 :         if (NS_SUCCEEDED(prefs->GetBoolPref(kSSOinPBmode, &ssoInPb)) &&
     108             :             ssoInPb) {
     109           0 :             return true;
     110             :         }
     111             : 
     112             :         bool dontRememberHistory;
     113           0 :         if (NS_SUCCEEDED(prefs->GetBoolPref("browser.privatebrowsing.autostart",
     114           0 :                                             &dontRememberHistory)) &&
     115           0 :             !dontRememberHistory) {
     116           0 :             return false;
     117             :         }
     118             :     }
     119             : 
     120           0 :     nsCOMPtr<nsIURI> uri;
     121           0 :     Unused << channel->GetURI(getter_AddRefs(uri));
     122             : 
     123             :     bool allowNonFqdn;
     124           0 :     if (NS_FAILED(prefs->GetBoolPref(kAllowNonFqdn, &allowNonFqdn)))
     125           0 :         allowNonFqdn = false;
     126           0 :     if (allowNonFqdn && uri && IsNonFqdn(uri)) {
     127           0 :         LOG(("Host is non-fqdn, default credentials are allowed\n"));
     128           0 :         return true;
     129             :     }
     130             : 
     131           0 :     bool isTrustedHost = (uri && auth::URIMatchesPrefPattern(uri, kTrustedURIs));
     132           0 :     LOG(("Default credentials allowed for host: %d\n", isTrustedHost));
     133           0 :     return isTrustedHost;
     134             : }
     135             : 
     136             : // Dummy class for session state object.  This class doesn't hold any data.
     137             : // Instead we use its existence as a flag.  See ChallengeReceived.
     138           0 : class nsNTLMSessionState final : public nsISupports
     139             : {
     140           0 :     ~nsNTLMSessionState() {}
     141             : public:
     142             :     NS_DECL_ISUPPORTS
     143             : };
     144           0 : NS_IMPL_ISUPPORTS0(nsNTLMSessionState)
     145             : 
     146             : //-----------------------------------------------------------------------------
     147             : 
     148           0 : NS_IMPL_ISUPPORTS(nsHttpNTLMAuth, nsIHttpAuthenticator)
     149             : 
     150             : NS_IMETHODIMP
     151           0 : nsHttpNTLMAuth::ChallengeReceived(nsIHttpAuthenticableChannel *channel,
     152             :                                   const char     *challenge,
     153             :                                   bool            isProxyAuth,
     154             :                                   nsISupports   **sessionState,
     155             :                                   nsISupports   **continuationState,
     156             :                                   bool           *identityInvalid)
     157             : {
     158           0 :     LOG(("nsHttpNTLMAuth::ChallengeReceived [ss=%p cs=%p]\n",
     159             :          *sessionState, *continuationState));
     160             : 
     161             :     // Use the native NTLM if available
     162           0 :     mUseNative = true;
     163             : 
     164             :     // NOTE: we don't define any session state, but we do use the pointer.
     165             : 
     166           0 :     *identityInvalid = false;
     167             : 
     168             :     // Start a new auth sequence if the challenge is exactly "NTLM".
     169             :     // If native NTLM auth apis are available and enabled through prefs,
     170             :     // try to use them.
     171           0 :     if (PL_strcasecmp(challenge, "NTLM") == 0) {
     172           0 :         nsCOMPtr<nsISupports> module;
     173             : 
     174             :         // Check to see if we should default to our generic NTLM auth module
     175             :         // through UseGenericNTLM. (We use native auth by default if the
     176             :         // system provides it.) If *sessionState is non-null, we failed to
     177             :         // instantiate a native NTLM module the last time, so skip trying again.
     178           0 :         bool forceGeneric = ForceGenericNTLM();
     179           0 :         if (!forceGeneric && !*sessionState) {
     180             :             // Check for approved default credentials hosts and proxies. If
     181             :             // *continuationState is non-null, the last authentication attempt
     182             :             // failed so skip default credential use.
     183           0 :             if (!*continuationState && CanUseDefaultCredentials(channel, isProxyAuth)) {
     184             :                 // Try logging in with the user's default credentials. If
     185             :                 // successful, |identityInvalid| is false, which will trigger
     186             :                 // a default credentials attempt once we return.
     187           0 :                 module = do_CreateInstance(NS_AUTH_MODULE_CONTRACTID_PREFIX "sys-ntlm");
     188             :             }
     189             : #ifdef XP_WIN
     190             :             else {
     191             :                 // Try to use native NTLM and prompt the user for their domain,
     192             :                 // username, and password. (only supported by windows nsAuthSSPI module.)
     193             :                 // Note, for servers that use LMv1 a weak hash of the user's password
     194             :                 // will be sent. We rely on windows internal apis to decide whether
     195             :                 // we should support this older, less secure version of the protocol.
     196             :                 module = do_CreateInstance(NS_AUTH_MODULE_CONTRACTID_PREFIX "sys-ntlm");
     197             :                 *identityInvalid = true;
     198             :             }
     199             : #endif // XP_WIN
     200           0 :             if (!module)
     201           0 :                 LOG(("Native sys-ntlm auth module not found.\n"));
     202             :         }
     203             : 
     204             : #ifdef XP_WIN
     205             :         // On windows, never fall back unless the user has specifically requested so.
     206             :         if (!forceGeneric && !module)
     207             :             return NS_ERROR_UNEXPECTED;
     208             : #endif
     209             : 
     210             :         // If no native support was available. Fall back on our internal NTLM implementation.
     211           0 :         if (!module) {
     212           0 :             if (!*sessionState) {
     213             :                 // Remember the fact that we cannot use the "sys-ntlm" module,
     214             :                 // so we don't ever bother trying again for this auth domain.
     215           0 :                 *sessionState = new nsNTLMSessionState();
     216           0 :                 if (!*sessionState)
     217           0 :                     return NS_ERROR_OUT_OF_MEMORY;
     218           0 :                 NS_ADDREF(*sessionState);
     219             :             }
     220             : 
     221             :             // Use our internal NTLM implementation. Note, this is less secure,
     222             :             // see bug 520607 for details.
     223           0 :             LOG(("Trying to fall back on internal ntlm auth.\n"));
     224           0 :             module = do_CreateInstance(NS_AUTH_MODULE_CONTRACTID_PREFIX "ntlm");
     225             : 
     226           0 :             mUseNative = false;
     227             : 
     228             :             // Prompt user for domain, username, and password.
     229           0 :             *identityInvalid = true;
     230             :         }
     231             : 
     232             :         // If this fails, then it means that we cannot do NTLM auth.
     233           0 :         if (!module) {
     234           0 :             LOG(("No ntlm auth modules available.\n"));
     235           0 :             return NS_ERROR_UNEXPECTED;
     236             :         }
     237             : 
     238             :         // A non-null continuation state implies that we failed to authenticate.
     239             :         // Blow away the old authentication state, and use the new one.
     240           0 :         module.swap(*continuationState);
     241             :     }
     242           0 :     return NS_OK;
     243             : }
     244             : 
     245             : NS_IMETHODIMP
     246           0 : nsHttpNTLMAuth::GenerateCredentialsAsync(nsIHttpAuthenticableChannel *authChannel,
     247             :                                          nsIHttpAuthenticatorCallback* aCallback,
     248             :                                          const char *challenge,
     249             :                                          bool isProxyAuth,
     250             :                                          const char16_t *domain,
     251             :                                          const char16_t *username,
     252             :                                          const char16_t *password,
     253             :                                          nsISupports *sessionState,
     254             :                                          nsISupports *continuationState,
     255             :                                          nsICancelable **aCancellable)
     256             : {
     257           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     258             : }
     259             : 
     260             : NS_IMETHODIMP
     261           0 : nsHttpNTLMAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
     262             :                                     const char      *challenge,
     263             :                                     bool             isProxyAuth,
     264             :                                     const char16_t *domain,
     265             :                                     const char16_t *user,
     266             :                                     const char16_t *pass,
     267             :                                     nsISupports    **sessionState,
     268             :                                     nsISupports    **continuationState,
     269             :                                     uint32_t       *aFlags,
     270             :                                     char           **creds)
     271             : 
     272             : {
     273           0 :     LOG(("nsHttpNTLMAuth::GenerateCredentials\n"));
     274             : 
     275           0 :     *creds = nullptr;
     276           0 :     *aFlags = 0;
     277             : 
     278             :     // if user or password is empty, ChallengeReceived returned
     279             :     // identityInvalid = false, that means we are using default user
     280             :     // credentials; see  nsAuthSSPI::Init method for explanation of this
     281             :     // condition
     282           0 :     if (!user || !pass)
     283           0 :         *aFlags = USING_INTERNAL_IDENTITY;
     284             : 
     285             :     nsresult rv;
     286           0 :     nsCOMPtr<nsIAuthModule> module = do_QueryInterface(*continuationState, &rv);
     287           0 :     NS_ENSURE_SUCCESS(rv, rv);
     288             : 
     289             :     void *inBuf, *outBuf;
     290             :     uint32_t inBufLen, outBufLen;
     291             : 
     292             :     // initial challenge
     293           0 :     if (PL_strcasecmp(challenge, "NTLM") == 0) {
     294             :         // NTLM service name format is 'HTTP@host' for both http and https
     295           0 :         nsCOMPtr<nsIURI> uri;
     296           0 :         rv = authChannel->GetURI(getter_AddRefs(uri));
     297           0 :         if (NS_FAILED(rv))
     298           0 :             return rv;
     299           0 :         nsAutoCString serviceName, host;
     300           0 :         rv = uri->GetAsciiHost(host);
     301           0 :         if (NS_FAILED(rv))
     302           0 :             return rv;
     303           0 :         serviceName.AppendLiteral("HTTP@");
     304           0 :         serviceName.Append(host);
     305             :         // initialize auth module
     306           0 :         uint32_t reqFlags = nsIAuthModule::REQ_DEFAULT;
     307           0 :         if (isProxyAuth)
     308           0 :             reqFlags |= nsIAuthModule::REQ_PROXY_AUTH;
     309             : 
     310           0 :         rv = module->Init(serviceName.get(), reqFlags, domain, user, pass);
     311           0 :         if (NS_FAILED(rv))
     312           0 :             return rv;
     313             : 
     314             : // This update enables updated Windows machines (Win7 or patched previous
     315             : // versions) and Linux machines running Samba (updated for Channel
     316             : // Binding), to perform Channel Binding when authenticating using NTLMv2
     317             : // and an outer secure channel.
     318             : //
     319             : // Currently only implemented for Windows, linux support will be landing in
     320             : // a separate patch, update this #ifdef accordingly then.
     321             : #if defined (XP_WIN) /* || defined (LINUX) */
     322             :         // We should retrieve the server certificate and compute the CBT,
     323             :         // but only when we are using the native NTLM implementation and
     324             :         // not the internal one.
     325             :         // It is a valid case not having the security info object.  This
     326             :         // occures when we connect an https site through an ntlm proxy.
     327             :         // After the ssl tunnel has been created, we get here the second
     328             :         // time and now generate the CBT from now valid security info.
     329             :         nsCOMPtr<nsIChannel> channel = do_QueryInterface(authChannel, &rv);
     330             :         if (NS_FAILED(rv))
     331             :             return rv;
     332             : 
     333             :         nsCOMPtr<nsISupports> security;
     334             :         rv = channel->GetSecurityInfo(getter_AddRefs(security));
     335             :         if (NS_FAILED(rv))
     336             :             return rv;
     337             : 
     338             :         nsCOMPtr<nsISSLStatusProvider> statusProvider =
     339             :             do_QueryInterface(security);
     340             : 
     341             :         if (mUseNative && statusProvider) {
     342             :             nsCOMPtr<nsISSLStatus> status;
     343             :             rv = statusProvider->GetSSLStatus(getter_AddRefs(status));
     344             :             if (NS_FAILED(rv))
     345             :                 return rv;
     346             : 
     347             :             nsCOMPtr<nsIX509Cert> cert;
     348             :             rv = status->GetServerCert(getter_AddRefs(cert));
     349             :             if (NS_FAILED(rv))
     350             :                 return rv;
     351             : 
     352             :             uint32_t length;
     353             :             uint8_t* certArray;
     354             :             cert->GetRawDER(&length, &certArray);
     355             : 
     356             :             // If there is a server certificate, we pass it along the
     357             :             // first time we call GetNextToken().
     358             :             inBufLen = length;
     359             :             inBuf = certArray;
     360             :         } else {
     361             :             // If there is no server certificate, we don't pass anything.
     362             :             inBufLen = 0;
     363             :             inBuf = nullptr;
     364             :         }
     365             : #else // Extended protection update is just for Linux and Windows machines.
     366           0 :         inBufLen = 0;
     367           0 :         inBuf = nullptr;
     368             : #endif
     369             :     }
     370             :     else {
     371             :         // decode challenge; skip past "NTLM " to the start of the base64
     372             :         // encoded data.
     373           0 :         int len = strlen(challenge);
     374           0 :         if (len < 6)
     375           0 :             return NS_ERROR_UNEXPECTED; // bogus challenge
     376           0 :         challenge += 5;
     377           0 :         len -= 5;
     378             : 
     379             :         // strip off any padding (see bug 230351)
     380           0 :         while (challenge[len - 1] == '=')
     381           0 :           len--;
     382             : 
     383             :         // decode into the input secbuffer
     384           0 :         rv = Base64Decode(challenge, len, (char**)&inBuf, &inBufLen);
     385           0 :         if (NS_FAILED(rv)) {
     386           0 :             return rv;
     387             :         }
     388             :     }
     389             : 
     390           0 :     rv = module->GetNextToken(inBuf, inBufLen, &outBuf, &outBufLen);
     391           0 :     if (NS_SUCCEEDED(rv)) {
     392             :         // base64 encode data in output buffer and prepend "NTLM "
     393           0 :         CheckedUint32 credsLen = ((CheckedUint32(outBufLen) + 2) / 3) * 4;
     394           0 :         credsLen += 5; // "NTLM "
     395           0 :         credsLen += 1; // null terminate
     396             : 
     397           0 :         if (!credsLen.isValid()) {
     398           0 :           rv = NS_ERROR_FAILURE;
     399             :         } else {
     400           0 :           *creds = (char *) moz_xmalloc(credsLen.value());
     401           0 :           memcpy(*creds, "NTLM ", 5);
     402           0 :           PL_Base64Encode((char *) outBuf, outBufLen, *creds + 5);
     403           0 :           (*creds)[credsLen.value() - 1] = '\0'; // null terminate
     404             :         }
     405             : 
     406             :         // OK, we are done with |outBuf|
     407           0 :         free(outBuf);
     408             :     }
     409             : 
     410           0 :     if (inBuf)
     411           0 :         free(inBuf);
     412             : 
     413           0 :     return rv;
     414             : }
     415             : 
     416             : NS_IMETHODIMP
     417           0 : nsHttpNTLMAuth::GetAuthFlags(uint32_t *flags)
     418             : {
     419           0 :     *flags = CONNECTION_BASED | IDENTITY_INCLUDES_DOMAIN | IDENTITY_ENCRYPTED;
     420           0 :     return NS_OK;
     421             : }
     422             : 
     423             : } // namespace net
     424             : } // namespace mozilla

Generated by: LCOV version 1.13