Bug 887984 - Send telemetry data from NTLM Init() methods. r=honzab
authorAdrian Lungu <alungu@mozilla.com>
Thu, 25 Jul 2013 09:54:11 -0700
changeset 140445 6364e33d76f5b456cd78377402727df544351d1d
parent 140444 a69d0630fb0616ee55002c57dfdeae4a5169c52c
child 140446 1774aaaad96a25a102a86bc611e113fece8755d5
push idunknown
push userunknown
push dateunknown
reviewershonzab
bugs887984
milestone25.0a1
Bug 887984 - Send telemetry data from NTLM Init() methods. r=honzab
extensions/auth/nsAuthGSSAPI.cpp
extensions/auth/nsAuthSSPI.cpp
extensions/auth/nsAuthSSPI.h
extensions/auth/nsAuthSambaNTLM.cpp
extensions/auth/nsHttpNegotiateAuth.cpp
netwerk/base/public/nsIAuthModule.idl
netwerk/protocol/http/nsHttpNTLMAuth.cpp
security/manager/ssl/src/nsNTLMAuthModule.cpp
toolkit/components/telemetry/Histograms.json
--- a/extensions/auth/nsAuthGSSAPI.cpp
+++ b/extensions/auth/nsAuthGSSAPI.cpp
@@ -17,16 +17,17 @@
 #include "mozilla/Util.h"
 
 #include "prlink.h"
 #include "nsCOMPtr.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsIServiceManager.h"
 #include "nsNativeCharsetUtils.h"
+#include "mozilla/Telemetry.h"
 
 #include "nsAuthGSSAPI.h"
 
 #ifdef XP_MACOSX
 #include <Kerberos/Kerberos.h>
 #endif
 
 #ifdef XP_MACOSX
@@ -348,16 +349,27 @@ nsAuthGSSAPI::Init(const char *serviceNa
 
     LOG(("entering nsAuthGSSAPI::Init()\n"));
 
     if (!gssLibrary)
        return NS_ERROR_NOT_INITIALIZED;
 
     mServiceName = serviceName;
     mServiceFlags = serviceFlags;
+
+    static bool sTelemetrySent = false;
+    if (!sTelemetrySent) {
+        mozilla::Telemetry::Accumulate(
+            mozilla::Telemetry::NTLM_MODULE_USED,
+            serviceFlags | nsIAuthModule::REQ_PROXY_AUTH
+                ? NTLM_MODULE_KERBEROS_PROXY
+                : NTLM_MODULE_KERBEROS_DIRECT);
+        sTelemetrySent = true;
+    }
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAuthGSSAPI::GetNextToken(const void *inToken,
                            uint32_t    inTokenLen,
                            void      **outToken,
                            uint32_t   *outTokenLen)
--- a/extensions/auth/nsAuthSSPI.cpp
+++ b/extensions/auth/nsAuthSSPI.cpp
@@ -15,16 +15,17 @@
 
 #include "nsAuthSSPI.h"
 #include "nsIServiceManager.h"
 #include "nsIDNSService.h"
 #include "nsIDNSRecord.h"
 #include "nsNetCID.h"
 #include "nsCOMPtr.h"
 #include "nsICryptoHash.h"
+#include "mozilla/Telemetry.h"
 
 #include <windows.h>
 
 #define SEC_SUCCESS(Status) ((Status) >= 0)
 
 #ifndef KERB_WRAP_NO_ENCRYPT
 #define KERB_WRAP_NO_ENCRYPT 0x80000001
 #endif
@@ -234,17 +235,17 @@ nsAuthSSPI::Init(const char *serviceName
     rc = (sspi->QuerySecurityPackageInfoW)(package, &pinfo);
     if (rc != SEC_E_OK) {
         LOG(("%s package not found\n", package));
         return NS_ERROR_UNEXPECTED;
     }
     mMaxTokenLen = pinfo->cbMaxToken;
     (sspi->FreeContextBuffer)(pinfo);
 
-    TimeStamp useBefore;
+    MS_TimeStamp useBefore;
 
     SEC_WINNT_AUTH_IDENTITY_W ai;
     SEC_WINNT_AUTH_IDENTITY_W *pai = nullptr;
     
     // domain, username, and password will be null if nsHttpNTLMAuth's ChallengeReceived
     // returns false for identityInvalid. Use default credentials in this case by passing
     // null for pai.
     if (username && password) {
@@ -268,16 +269,27 @@ nsAuthSSPI::Init(const char *serviceName
                                            nullptr,
                                            pai,
                                            nullptr,
                                            nullptr,
                                            &mCred,
                                            &useBefore);
     if (rc != SEC_E_OK)
         return NS_ERROR_UNEXPECTED;
+
+    static bool sTelemetrySent = false;
+    if (!sTelemetrySent) {
+        mozilla::Telemetry::Accumulate(
+            mozilla::Telemetry::NTLM_MODULE_USED,
+            serviceFlags | nsIAuthModule::REQ_PROXY_AUTH
+                ? NTLM_MODULE_WIN_API_PROXY
+                : NTLM_MODULE_WIN_API_DIRECT);
+        sTelemetrySent = true;
+    }
+
     LOG(("AcquireCredentialsHandle() succeeded.\n"));
     return NS_OK;
 }
 
 // The arguments inToken and inTokenLen are used to pass in the server
 // certificate (when available) in the first call of the function. The
 // second time these arguments hold an input token. 
 NS_IMETHODIMP
@@ -288,17 +300,17 @@ nsAuthSSPI::GetNextToken(const void *inT
 {
     // String for end-point bindings.
     const char end_point[] = "tls-server-end-point:"; 
     const int end_point_length = sizeof(end_point) - 1;
     const int hash_size = 32;  // Size of a SHA256 hash.
     const int cbt_size = hash_size + end_point_length;
 	
     SECURITY_STATUS rc;
-    TimeStamp ignored;
+    MS_TimeStamp ignored;
 
     DWORD ctxAttr, ctxReq = 0;
     CtxtHandle *ctxIn;
     SecBufferDesc ibd, obd;
     // Optional second input buffer for the CBT (Channel Binding Token)
     SecBuffer ib[2], ob;
     // Pointer to the block of memory that stores the CBT
     char* sspi_cbt = nullptr;
--- a/extensions/auth/nsAuthSSPI.h
+++ b/extensions/auth/nsAuthSSPI.h
@@ -34,16 +34,18 @@ public:
 
     nsAuthSSPI(pType package = PACKAGE_TYPE_NEGOTIATE);
 
 private:
     ~nsAuthSSPI();
 
     void Reset();
 
+    typedef TimeStamp MS_TimeStamp;
+
 private:
     CredHandle   mCred;
     CtxtHandle   mCtxt;
     nsCString    mServiceName;
     uint32_t     mServiceFlags;
     uint32_t     mMaxTokenLen;
     pType        mPackage;
     nsString     mDomain;
--- a/extensions/auth/nsAuthSambaNTLM.cpp
+++ b/extensions/auth/nsAuthSambaNTLM.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsAuth.h"
 #include "nsAuthSambaNTLM.h"
 #include "prenv.h"
 #include "plbase64.h"
 #include "prerror.h"
+#include "mozilla/Telemetry.h"
 
 #include <stdlib.h>
 
 nsAuthSambaNTLM::nsAuthSambaNTLM()
     : mInitialMessage(nullptr), mChildPID(nullptr), mFromChildFD(nullptr),
       mToChildFD(nullptr)
 {
 }
@@ -205,16 +206,27 @@ nsAuthSambaNTLM::SpawnNTLMAuthHelper()
 NS_IMETHODIMP
 nsAuthSambaNTLM::Init(const char *serviceName,
                       uint32_t    serviceFlags,
                       const PRUnichar *domain,
                       const PRUnichar *username,
                       const PRUnichar *password)
 {
     NS_ASSERTION(!username && !domain && !password, "unexpected credentials");
+
+    static bool sTelemetrySent = false;
+    if (!sTelemetrySent) {
+        mozilla::Telemetry::Accumulate(
+            mozilla::Telemetry::NTLM_MODULE_USED,
+            serviceFlags | nsIAuthModule::REQ_PROXY_AUTH
+                ? NTLM_MODULE_SAMBA_AUTH_PROXY
+                : NTLM_MODULE_SAMBA_AUTH_DIRECT);
+        sTelemetrySent = true;
+    }
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAuthSambaNTLM::GetNextToken(const void *inToken,
                               uint32_t    inTokenLen,
                               void      **outToken,
                               uint32_t   *outTokenLen)
--- a/extensions/auth/nsHttpNegotiateAuth.cpp
+++ b/extensions/auth/nsHttpNegotiateAuth.cpp
@@ -99,16 +99,17 @@ nsHttpNegotiateAuth::ChallengeReceived(n
     nsAutoCString service;
 
     if (isProxyAuth) {
         if (!TestBoolPref(kNegotiateAuthAllowProxies)) {
             LOG(("nsHttpNegotiateAuth::ChallengeReceived proxy auth blocked\n"));
             return NS_ERROR_ABORT;
         }
 
+        req_flags |= nsIAuthModule::REQ_PROXY_AUTH;
         nsCOMPtr<nsIProxyInfo> proxyInfo;
         authChannel->GetProxyInfo(getter_AddRefs(proxyInfo));
         NS_ENSURE_STATE(proxyInfo);
 
         proxyInfo->GetHost(service);
     }
     else {
         bool allowed = TestNonFqdn(uri) ||
--- a/netwerk/base/public/nsIAuthModule.idl
+++ b/netwerk/base/public/nsIAuthModule.idl
@@ -19,16 +19,33 @@ interface nsIAuthModule : nsISupports
 
     /**
      * The server is allowed to impersonate the client.  The REQ_MUTUAL_AUTH
      * flag may also need to be specified in order for this flag to take
      * effect.
      */
     const unsigned long REQ_DELEGATE = (1 << 1);
 
+    /**
+     * The authentication is required for a proxy connection.
+     */
+    const unsigned long REQ_PROXY_AUTH = (1 << 2);
+
+    /**
+     * Flags used for telemetry.
+     */
+    const unsigned long NTLM_MODULE_SAMBA_AUTH_PROXY = 0;
+    const unsigned long NTLM_MODULE_SAMBA_AUTH_DIRECT = 1;
+    const unsigned long NTLM_MODULE_WIN_API_PROXY = 2;
+    const unsigned long NTLM_MODULE_WIN_API_DIRECT = 3;
+    const unsigned long NTLM_MODULE_GENERIC_PROXY = 4;
+    const unsigned long NTLM_MODULE_GENERIC_DIRECT = 5;
+    const unsigned long NTLM_MODULE_KERBEROS_PROXY = 6;
+    const unsigned long NTLM_MODULE_KERBEROS_DIRECT = 7;
+
     /** Other flags may be defined in the future */
 
     /**
      * Called to initialize an auth module.  The other methods cannot be called
      * unless this method succeeds.
      *
      * @param aServiceName
      *        the service name, which may be null if not applicable (e.g., for
--- a/netwerk/protocol/http/nsHttpNTLMAuth.cpp
+++ b/netwerk/protocol/http/nsHttpNTLMAuth.cpp
@@ -359,17 +359,21 @@ nsHttpNTLMAuth::GenerateCredentials(nsIH
             return rv;
         nsAutoCString serviceName, host;
         rv = uri->GetAsciiHost(host);
         if (NS_FAILED(rv))
             return rv;
         serviceName.AppendLiteral("HTTP@");
         serviceName.Append(host);
         // initialize auth module
-        rv = module->Init(serviceName.get(), nsIAuthModule::REQ_DEFAULT, domain, user, pass);
+        uint32_t reqFlags = nsIAuthModule::REQ_DEFAULT;
+        if (isProxyAuth)
+            reqFlags |= nsIAuthModule::REQ_PROXY_AUTH;
+
+        rv = module->Init(serviceName.get(), reqFlags, domain, user, pass);
         if (NS_FAILED(rv))
             return rv;
 
 // This update enables updated Windows machines (Win7 or patched previous
 // versions) and Linux machines running Samba (updated for Channel
 // Binding), to perform Channel Binding when authenticating using NTLMv2
 // and an outer secure channel.
 //
--- a/security/manager/ssl/src/nsNTLMAuthModule.cpp
+++ b/security/manager/ssl/src/nsNTLMAuthModule.cpp
@@ -7,16 +7,17 @@
 
 #include "nsNTLMAuthModule.h"
 #include "nsNSSShutDown.h"
 #include "nsNativeCharsetUtils.h"
 #include "prsystem.h"
 #include "pk11pub.h"
 #include "md4.h"
 #include "mozilla/Likely.h"
+#include "mozilla/Telemetry.h"
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo *
 GetNTLMLog()
 {
   static PRLogModuleInfo *sNTLMLog;
   if (!sNTLMLog)
     sNTLMLog = PR_NewLogModule("NTLM");
@@ -762,21 +763,33 @@ nsNTLMAuthModule::InitTest()
 
 NS_IMETHODIMP
 nsNTLMAuthModule::Init(const char      *serviceName,
                        uint32_t         serviceFlags,
                        const PRUnichar *domain,
                        const PRUnichar *username,
                        const PRUnichar *password)
 {
-  NS_ASSERTION(serviceFlags == nsIAuthModule::REQ_DEFAULT, "unexpected service flags");
+  NS_ASSERTION((serviceFlags & ~nsIAuthModule::REQ_PROXY_AUTH) == nsIAuthModule::REQ_DEFAULT,
+      "unexpected service flags");
 
   mDomain = domain;
   mUsername = username;
   mPassword = password;
+
+  static bool sTelemetrySent = false;
+  if (!sTelemetrySent) {
+      mozilla::Telemetry::Accumulate(
+          mozilla::Telemetry::NTLM_MODULE_USED,
+          serviceFlags | nsIAuthModule::REQ_PROXY_AUTH
+              ? NTLM_MODULE_GENERIC_PROXY
+              : NTLM_MODULE_GENERIC_DIRECT);
+      sTelemetrySent = true;
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNTLMAuthModule::GetNextToken(const void *inToken,
                                uint32_t    inTokenLen,
                                void      **outToken,
                                uint32_t   *outTokenLen)
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -3738,16 +3738,21 @@
     "kind": "boolean",
     "description": "The result of the startup default desktop browser check."
   },
   "MIXED_CONTENT_PAGE_LOAD": {
     "kind": "enumerated",
     "n_values": 4,
     "description": "Accumulates type of content (mixed, mixed passive, unmixed) per page load"
   },
+  "NTLM_MODULE_USED": {
+    "kind": "enumerated",
+    "n_values": 8,
+    "description": "The module used for the NTLM protocol (Windows_API, Kerberos, Samba_auth or Generic) and whether or not the authentication was used to connect to a proxy server. This data is collected only once per session (at first NTLM authentification)."
+  },
   "FX_THUMBNAILS_BG_QUEUE_SIZE_ON_CAPTURE": {
     "kind": "exponential",
     "high": 100,
     "n_buckets": 15,
     "extended_statistics_ok": true,
     "description": "BACKGROUND THUMBNAILS: Size of capture queue when a capture request is received"
   },
   "FX_THUMBNAILS_BG_CAPTURE_QUEUE_TIME_MS": {