bug 1239166 - platform work to support Microsoft Family Safety functionality r=froydnj,mgoodwin,mhowell,rbarnes,vladan

MozReview-Commit-ID: GhpJqJB97r9

--HG--
extra : rebase_source : e943c1e4d0f008ffd6b6bb4bb63e1daf27ae2c96
This commit is contained in:
David Keeler 2016-01-12 15:39:43 -08:00
Родитель 569b24a16f
Коммит 9825c57bc3
7 изменённых файлов: 504 добавлений и 20 удалений

Просмотреть файл

@ -171,6 +171,12 @@ IsWin8OrLater()
return IsWindowsVersionOrLater(0x06020000ul);
}
MOZ_ALWAYS_INLINE bool
IsWin8Point1OrLater()
{
return IsWindowsVersionOrLater(0x06030000ul);
}
MOZ_ALWAYS_INLINE bool
IsWin10OrLater()
{

Просмотреть файл

@ -513,7 +513,12 @@ nsNSSCertificate::GetDbKey(nsACString& aDbKey)
if (isAlreadyShutDown()) {
return NS_ERROR_NOT_AVAILABLE;
}
return GetDbKey(mCert, aDbKey);
}
nsresult
nsNSSCertificate::GetDbKey(CERTCertificate* cert, nsACString& aDbKey)
{
static_assert(sizeof(uint64_t) == 8, "type size sanity check");
static_assert(sizeof(uint32_t) == 4, "type size sanity check");
// The format of the key is the base64 encoding of the following:
@ -528,14 +533,14 @@ nsNSSCertificate::GetDbKey(nsACString& aDbKey)
nsAutoCString buf;
const char leadingZeroes[] = {0, 0, 0, 0, 0, 0, 0, 0};
buf.Append(leadingZeroes, sizeof(leadingZeroes));
uint32_t serialNumberLen = htonl(mCert->serialNumber.len);
uint32_t serialNumberLen = htonl(cert->serialNumber.len);
buf.Append(reinterpret_cast<const char*>(&serialNumberLen), sizeof(uint32_t));
uint32_t issuerLen = htonl(mCert->derIssuer.len);
uint32_t issuerLen = htonl(cert->derIssuer.len);
buf.Append(reinterpret_cast<const char*>(&issuerLen), sizeof(uint32_t));
buf.Append(reinterpret_cast<const char*>(mCert->serialNumber.data),
mCert->serialNumber.len);
buf.Append(reinterpret_cast<const char*>(mCert->derIssuer.data),
mCert->derIssuer.len);
buf.Append(reinterpret_cast<const char*>(cert->serialNumber.data),
cert->serialNumber.len);
buf.Append(reinterpret_cast<const char*>(cert->derIssuer.data),
cert->derIssuer.len);
return Base64Encode(buf, aDbKey);
}

Просмотреть файл

@ -53,6 +53,10 @@ public:
ev_status_unknown = 2
};
// This is a separate static method so nsNSSComponent can use it during NSS
// initialization. Other code should probably not use it.
static nsresult GetDbKey(CERTCertificate* cert, nsACString& aDbKey);
private:
virtual ~nsNSSCertificate();

Просмотреть файл

@ -128,10 +128,10 @@ nsNSSCertificateDB::FindCertByNickname(const nsAString& nickname,
}
NS_IMETHODIMP
nsNSSCertificateDB::FindCertByDBKey(const char* aDBkey,nsIX509Cert** _cert)
nsNSSCertificateDB::FindCertByDBKey(const char* aDBKey,nsIX509Cert** _cert)
{
NS_ENSURE_ARG_POINTER(aDBkey);
NS_ENSURE_ARG(aDBkey[0]);
NS_ENSURE_ARG_POINTER(aDBKey);
NS_ENSURE_ARG(aDBKey[0]);
NS_ENSURE_ARG_POINTER(_cert);
*_cert = nullptr;
@ -140,6 +140,27 @@ nsNSSCertificateDB::FindCertByDBKey(const char* aDBkey,nsIX509Cert** _cert)
return NS_ERROR_NOT_AVAILABLE;
}
UniqueCERTCertificate cert;
nsresult rv = FindCertByDBKey(aDBKey, cert);
if (NS_FAILED(rv)) {
return rv;
}
// If we can't find the certificate, that's not an error. Just return null.
if (!cert) {
return NS_OK;
}
nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
if (!nssCert) {
return NS_ERROR_OUT_OF_MEMORY;
}
nssCert.forget(_cert);
return NS_OK;
}
nsresult
nsNSSCertificateDB::FindCertByDBKey(const char* aDBKey,
UniqueCERTCertificate& cert)
{
static_assert(sizeof(uint64_t) == 8, "type size sanity check");
static_assert(sizeof(uint32_t) == 4, "type size sanity check");
// (From nsNSSCertificate::GetDbKey)
@ -153,7 +174,7 @@ nsNSSCertificateDB::FindCertByDBKey(const char* aDBkey,nsIX509Cert** _cert)
// n bytes: <bytes of serial number>
// m bytes: <DER-encoded issuer distinguished name>
nsAutoCString decoded;
nsAutoCString tmpDBKey(aDBkey);
nsAutoCString tmpDBKey(aDBKey);
// Filter out any whitespace for backwards compatibility.
tmpDBKey.StripWhitespace();
nsresult rv = Base64Decode(tmpDBKey, decoded);
@ -185,15 +206,7 @@ nsNSSCertificateDB::FindCertByDBKey(const char* aDBkey,nsIX509Cert** _cert)
reader += issuerLen;
MOZ_ASSERT(reader == decoded.EndReading());
ScopedCERTCertificate cert(
CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN));
if (cert) {
nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
if (!nssCert) {
return NS_ERROR_OUT_OF_MEMORY;
}
nssCert.forget(_cert);
}
cert.reset(CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN));
return NS_OK;
}

Просмотреть файл

@ -35,6 +35,11 @@ public:
ImportValidCACerts(int numCACerts, SECItem *CACerts, nsIInterfaceRequestor *ctx,
const nsNSSShutDownPreventionLock &proofOfLock);
// This is a separate static method so nsNSSComponent can use it during NSS
// initialization. Other code should probably not use it.
static nsresult
FindCertByDBKey(const char* aDBKey, mozilla::UniqueCERTCertificate& cert);
protected:
virtual ~nsNSSCertificateDB();

Просмотреть файл

@ -4,16 +4,21 @@
* 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/. */
#define CERT_AddTempCertToPerm __CERT_AddTempCertToPerm
#include "nsNSSComponent.h"
#include "ExtendedValidation.h"
#include "NSSCertDBTrustDomain.h"
#include "SharedSSLState.h"
#include "cert.h"
#include "certdb.h"
#include "mozilla/Preferences.h"
#include "mozilla/PublicSSL.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/Telemetry.h"
#include "mozilla/UniquePtr.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsCRT.h"
#include "nsCertVerificationThread.h"
@ -30,6 +35,7 @@
#include "nsITokenPasswordDialogs.h"
#include "nsIWindowWatcher.h"
#include "nsIXULRuntime.h"
#include "nsNSSCertificateDB.h"
#include "nsNSSHelper.h"
#include "nsNSSShutDown.h"
#include "nsServiceManagerUtils.h"
@ -49,7 +55,14 @@
#endif
#ifdef XP_WIN
#include "mozilla/WindowsVersion.h"
#include "nsILocalFileWin.h"
#include "windows.h" // this needs to be before the following includes
#include "Lmcons.h"
#include "Sddl.h"
#include "Wincrypt.h"
#include "nsIWindowsRegKey.h"
#endif
using namespace mozilla;
@ -394,6 +407,433 @@ nsNSSComponent::ShutdownSmartCardThreads()
}
#endif // MOZ_NO_SMART_CARDS
#ifdef XP_WIN
static bool
GetUserSid(nsAString& sidString)
{
// UNLEN is the maximum user name length (see Lmcons.h). +1 for the null
// terminator.
WCHAR lpAccountName[UNLEN + 1];
DWORD lcAccountName = sizeof(lpAccountName) / sizeof(lpAccountName[0]);
BOOL success = GetUserName(lpAccountName, &lcAccountName);
if (!success) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("GetUserName failed"));
return false;
}
char sid_buffer[SECURITY_MAX_SID_SIZE];
SID* sid = reinterpret_cast<SID*>(sid_buffer);
DWORD cbSid = MOZ_ARRAY_LENGTH(sid_buffer);
SID_NAME_USE eUse;
// There doesn't appear to be a defined maximum length for the domain name
// here. To deal with this, we start with a reasonable buffer length and
// see if that works. If it fails and the error indicates insufficient length,
// we use the indicated required length and try again.
DWORD cchReferencedDomainName = 128;
auto ReferencedDomainName(MakeUnique<WCHAR[]>(cchReferencedDomainName));
success = LookupAccountName(nullptr, lpAccountName, sid, &cbSid,
ReferencedDomainName.get(),
&cchReferencedDomainName, &eUse);
if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("LookupAccountName failed"));
return false;
}
if (!success) {
ReferencedDomainName = MakeUnique<WCHAR[]>(cchReferencedDomainName);
success = LookupAccountName(nullptr, lpAccountName, sid, &cbSid,
ReferencedDomainName.get(),
&cchReferencedDomainName, &eUse);
}
if (!success) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("LookupAccountName failed"));
return false;
}
LPTSTR StringSid;
success = ConvertSidToStringSid(sid, &StringSid);
if (!success) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("ConvertSidToStringSid failed"));
return false;
}
sidString.Assign(StringSid);
LocalFree(StringSid);
return true;
}
// This is a specialized helper function to read the value of a registry key
// that might not be present. If it is present, returns (via the output
// parameter) its value. Otherwise, returns the given default value.
// This function handles one level of nesting. That is, if the desired value
// is actually in a direct child of the given registry key (where the child
// and/or the value being sought may not actually be present), this function
// will handle that. In the normal case, though, optionalChildName will be
// null.
static nsresult
ReadRegKeyValueWithDefault(nsCOMPtr<nsIWindowsRegKey> regKey,
uint32_t flags,
wchar_t* optionalChildName,
wchar_t* valueName,
uint32_t defaultValue,
uint32_t& valueOut)
{
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("ReadRegKeyValueWithDefault"));
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("attempting to read '%S%s%S' with default '%u'",
optionalChildName ? optionalChildName : L"",
optionalChildName ? "\\" : "", valueName, defaultValue));
if (optionalChildName) {
nsDependentString childNameString(optionalChildName);
bool hasChild;
nsresult rv = regKey->HasChild(childNameString, &hasChild);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("failed to determine if child key is present"));
return rv;
}
if (!hasChild) {
valueOut = defaultValue;
return NS_OK;
}
nsCOMPtr<nsIWindowsRegKey> childRegKey;
rv = regKey->OpenChild(childNameString, flags,
getter_AddRefs(childRegKey));
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't open child key"));
return rv;
}
return ReadRegKeyValueWithDefault(childRegKey, flags, nullptr, valueName,
defaultValue, valueOut);
}
nsDependentString valueNameString(valueName);
bool hasValue;
nsresult rv = regKey->HasValue(valueNameString, &hasValue);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("failed to determine if value is present"));
return rv;
}
if (!hasValue) {
valueOut = defaultValue;
return NS_OK;
}
rv = regKey->ReadIntValue(valueNameString, &valueOut);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed to read value"));
return rv;
}
return NS_OK;
}
static nsresult
AccountHasFamilySafetyEnabled(bool& enabled)
{
enabled = false;
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("AccountHasFamilySafetyEnabled?"));
nsCOMPtr<nsIWindowsRegKey> parentalControlsKey(
do_CreateInstance("@mozilla.org/windows-registry-key;1"));
if (!parentalControlsKey) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't create nsIWindowsRegKey"));
return NS_ERROR_FAILURE;
}
uint32_t flags = nsIWindowsRegKey::ACCESS_READ | nsIWindowsRegKey::WOW64_64;
NS_NAMED_LITERAL_STRING(familySafetyPath,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Parental Controls");
nsresult rv = parentalControlsKey->Open(
nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, familySafetyPath, flags);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't open parentalControlsKey"));
return rv;
}
NS_NAMED_LITERAL_STRING(usersString, "Users");
bool hasUsers;
rv = parentalControlsKey->HasChild(usersString, &hasUsers);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("HasChild(Users) failed"));
return rv;
}
if (!hasUsers) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("Users subkey not present - Parental Controls not enabled"));
return NS_OK;
}
nsCOMPtr<nsIWindowsRegKey> usersKey;
rv = parentalControlsKey->OpenChild(usersString, flags,
getter_AddRefs(usersKey));
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed to open Users subkey"));
return rv;
}
nsAutoString sid;
if (!GetUserSid(sid)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get sid"));
return NS_ERROR_FAILURE;
}
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("our sid is '%S'", sid.get()));
bool hasSid;
rv = usersKey->HasChild(sid, &hasSid);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("HasChild(sid) failed"));
return rv;
}
if (!hasSid) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("sid not present in Family Safety Users"));
return NS_OK;
}
nsCOMPtr<nsIWindowsRegKey> sidKey;
rv = usersKey->OpenChild(sid, flags, getter_AddRefs(sidKey));
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't open sid key"));
return rv;
}
// There are three keys we're interested in: "Parental Controls On",
// "Logging Required", and "Web\\Filter On". These keys will have value 0
// or 1, indicating a particular feature is disabled or enabled,
// respectively. So, if "Parental Controls On" is not 1, Family Safety is
// disabled and we don't care about anything else. If both "Logging
// Required" and "Web\\Filter On" are 0, the proxy will not be running,
// so for our purposes we can consider Family Safety disabled in that
// case.
// By default, "Logging Required" is 1 and "Web\\Filter On" is 0,
// reflecting the initial settings when Family Safety is enabled for an
// account for the first time, However, these sub-keys are not created
// unless they are switched away from the default value.
uint32_t parentalControlsOn;
rv = sidKey->ReadIntValue(NS_LITERAL_STRING("Parental Controls On"),
&parentalControlsOn);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("couldn't read Parental Controls On"));
return rv;
}
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("Parental Controls On: %u", parentalControlsOn));
if (parentalControlsOn != 1) {
return NS_OK;
}
uint32_t loggingRequired;
rv = ReadRegKeyValueWithDefault(sidKey, flags, nullptr, L"Logging Required",
1, loggingRequired);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("failed to read value of Logging Required"));
return rv;
}
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("Logging Required: %u", loggingRequired));
uint32_t webFilterOn;
rv = ReadRegKeyValueWithDefault(sidKey, flags, L"Web", L"Filter On", 0,
webFilterOn);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("failed to read value of Web\\Filter On"));
return rv;
}
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Web\\Filter On: %u", webFilterOn));
enabled = loggingRequired == 1 || webFilterOn == 1;
return NS_OK;
}
const char* kImportedFamilySafetyRootPref =
"security.family_safety.imported_root.db_key";
static nsresult
MaybeImportFamilySafetyRoot(PCCERT_CONTEXT certificate,
bool& wasFamilySafetyRoot)
{
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("MaybeImportFamilySafetyRoot"));
wasFamilySafetyRoot = false;
// It would be convenient to just use nsIX509CertDB here. However, since
// nsIX509CertDB depends on nsNSSComponent initialization, we can't use it.
// Instead, we can use NSS APIs directly (as long as we're called late enough
// in nsNSSComponent initialization such that those APIs are safe to use).
SECItem derCert = {
siBuffer,
certificate->pbCertEncoded,
certificate->cbCertEncoded
};
UniqueCERTCertificate nssCertificate(
CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert,
nullptr, // nickname unnecessary
false, // not permanent
true)); // copy DER
if (!nssCertificate) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't decode certificate"));
return NS_ERROR_FAILURE;
}
// Looking for a certificate with the common name 'Microsoft Family Safety'
UniquePtr<char, void(&)(void*)> subjectName(
CERT_GetCommonName(&nssCertificate->subject), PORT_Free);
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("subject name is '%s'", subjectName.get()));
if (nsCRT::strcmp(subjectName.get(), "Microsoft Family Safety") == 0) {
wasFamilySafetyRoot = true;
CERTCertTrust trust = {
CERTDB_TRUSTED_CA | CERTDB_VALID_CA | CERTDB_USER,
0,
0
};
SECStatus srv = __CERT_AddTempCertToPerm(
nssCertificate.get(), "Microsoft Family Safety", &trust);
if (srv != SECSuccess) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("couldn't permanently add certificate"));
return NS_ERROR_FAILURE;
}
nsAutoCString dbKey;
nsresult rv = nsNSSCertificate::GetDbKey(nssCertificate.get(), dbKey);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("GetDbKey failed"));
return rv;
}
Preferences::SetCString(kImportedFamilySafetyRootPref, dbKey);
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("added Family Safety root"));
}
return NS_OK;
}
// Because HCERTSTORE is just a typedef void*, we can't use any of the nice
// scoped pointer templates.
class ScopedCertStore final
{
public:
explicit ScopedCertStore(HCERTSTORE certstore) : certstore(certstore) {}
~ScopedCertStore()
{
CertCloseStore(certstore, 0);
}
HCERTSTORE get()
{
return certstore;
}
private:
ScopedCertStore(const ScopedCertStore&) = delete;
ScopedCertStore& operator=(const ScopedCertStore&) = delete;
HCERTSTORE certstore;
};
static const wchar_t* WindowsDefaultRootStoreName = L"ROOT";
static nsresult
LoadFamilySafetyRoot()
{
ScopedCertStore certstore(
CertOpenSystemStore(0, WindowsDefaultRootStoreName));
if (!certstore.get()) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("couldn't get certstore '%S'", WindowsDefaultRootStoreName));
return NS_ERROR_FAILURE;
}
// Any resources held by the certificate are released by the next call to
// CertFindCertificateInStore.
PCCERT_CONTEXT certificate = nullptr;
while (certificate = CertFindCertificateInStore(certstore.get(),
X509_ASN_ENCODING, 0,
CERT_FIND_ANY, nullptr,
certificate)) {
bool wasFamilySafetyRoot = false;
nsresult rv = MaybeImportFamilySafetyRoot(certificate,
wasFamilySafetyRoot);
if (NS_SUCCEEDED(rv) && wasFamilySafetyRoot) {
return NS_OK; // We're done (we're only expecting one root).
}
}
return NS_ERROR_FAILURE;
}
static void
UnloadFamilySafetyRoot()
{
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("UnloadFamilySafetyRoot"));
nsAdoptingCString dbKey = Preferences::GetCString(
kImportedFamilySafetyRootPref);
if (!dbKey || dbKey.IsEmpty()) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("Family Safety root wasn't previously imported"));
return;
}
UniqueCERTCertificate cert;
nsresult rv = nsNSSCertificateDB::FindCertByDBKey(dbKey, cert);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("finding previously-imported Family Safety root failed"));
return;
}
if (!cert) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("previously-imported Family Safety root not found"));
return;
}
SECStatus srv = SEC_DeletePermCertificate(cert.get());
if (srv != SECSuccess) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("couldn't delete previously-imported Family Safety root"));
return;
}
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("deleted previously-imported Family Safety root"));
Preferences::ClearUser(kImportedFamilySafetyRootPref);
}
#endif // XP_WIN
// The supported values of this pref are:
// 0: disable detecting Family Safety mode and importing the root
// 1: only attempt to detect Family Safety mode (don't import the root)
// 2: detect Family Safety mode and import the root
const char* kFamilySafetyModePref = "security.family_safety.mode";
// The telemetry gathered by this function is as follows:
// 0-2: the value of the Family Safety mode pref
// 3: detecting Family Safety mode failed
// 4: Family Safety was not enabled
// 5: Family Safety was enabled
// 6: failed to import the Family Safety root
// 7: successfully imported the root
static void
MaybeEnableFamilySafetyCompatibility()
{
#ifdef XP_WIN
UnloadFamilySafetyRoot();
if (!(IsWin8Point1OrLater() && !IsWin10OrLater())) {
return;
}
// Detect but don't import by default.
uint32_t familySafetyMode = Preferences::GetUint(kFamilySafetyModePref, 1);
if (familySafetyMode > 2) {
familySafetyMode = 0;
}
Telemetry::Accumulate(Telemetry::FAMILY_SAFETY, familySafetyMode);
if (familySafetyMode == 0) {
return;
}
bool familySafetyEnabled;
nsresult rv = AccountHasFamilySafetyEnabled(familySafetyEnabled);
if (NS_FAILED(rv)) {
Telemetry::Accumulate(Telemetry::FAMILY_SAFETY, 3);
return;
}
if (!familySafetyEnabled) {
Telemetry::Accumulate(Telemetry::FAMILY_SAFETY, 4);
return;
}
Telemetry::Accumulate(Telemetry::FAMILY_SAFETY, 5);
if (familySafetyMode == 2) {
rv = LoadFamilySafetyRoot();
if (NS_FAILED(rv)) {
Telemetry::Accumulate(Telemetry::FAMILY_SAFETY, 6);
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("failed to load Family Safety root"));
} else {
Telemetry::Accumulate(Telemetry::FAMILY_SAFETY, 7);
}
}
#endif // XP_WIN
}
void
nsNSSComponent::LoadLoadableRoots()
{
@ -1079,6 +1519,8 @@ nsNSSComponent::InitializeNSS()
InitCertVerifierLog();
LoadLoadableRoots();
MaybeEnableFamilySafetyCompatibility();
ConfigureTLSSessionIdentifiers();
bool requireSafeNegotiation =
@ -1144,7 +1586,6 @@ nsNSSComponent::InitializeNSS()
if (PK11_IsFIPS()) {
Telemetry::Accumulate(Telemetry::FIPS_ENABLED, true);
}
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("NSS Initialization done\n"));
return NS_OK;
}
@ -1346,6 +1787,8 @@ nsNSSComponent::Observe(nsISupports* aSubject, const char* aTopic,
MutexAutoLock lock(mutex);
mTestBuiltInRootHash = Preferences::GetString("security.test.built_in_root_hash");
#endif // DEBUG
} else if (prefName.Equals(kFamilySafetyModePref)) {
MaybeEnableFamilySafetyCompatibility();
} else {
clearSessionCache = false;
}

Просмотреть файл

@ -291,6 +291,14 @@
"n_values": 10,
"description": "GPU Device Reset Reason (ok, hung, removed, reset, internal error, invalid call, out of memory)"
},
"FAMILY_SAFETY": {
"alert_emails": ["seceng@mozilla.org"],
"expires_in_version": "55",
"kind": "enumerated",
"n_values": 16,
"bug_numbers": [1239166],
"description": "Status of Family Safety detection and remediation. See nsNSSComponent.cpp."
},
"FETCH_IS_MAINTHREAD": {
"expires_in_version": "50",
"kind": "boolean",