blob: 052c89c9473deacaf0fd0bd87225fbe81bf11dee [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/win/parental_controls.h"
#include <combaseapi.h>
#include <windows.h>
#include <winerror.h>
#include <wpcapi.h>
#include <wrl/client.h>
#include <string>
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/strings/stringprintf.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/win/registry.h"
#include "base/win/win_util.h"
#include "base/win/windows_types.h"
namespace {
// This singleton allows us to attempt to calculate the Platform Parental
// Controls enabled value on a worker thread before the UI thread needs the
// value. If the UI thread finishes sooner than we expect, that's no worse than
// today where we block.
class WinParentalControlsValue {
public:
static WinParentalControlsValue* GetInstance() {
return base::Singleton<WinParentalControlsValue>::get();
}
const WinParentalControls& parental_controls() const {
return parental_controls_;
}
private:
friend struct base::DefaultSingletonTraits<WinParentalControlsValue>;
WinParentalControlsValue() : parental_controls_(GetParentalControls()) {}
~WinParentalControlsValue() = default;
WinParentalControlsValue(const WinParentalControlsValue&) = delete;
WinParentalControlsValue& operator=(const WinParentalControlsValue&) = delete;
// Returns the Windows Parental control enablements. This feature is available
// on Windows 7 and beyond. This function should be called on a COM
// Initialized thread and is potentially blocking.
static WinParentalControls GetParentalControlsFromApi() {
// Since we can potentially block, make sure the thread is okay with this.
base::ScopedBlockingCall scoped_blocking_call(
FROM_HERE, base::BlockingType::MAY_BLOCK);
Microsoft::WRL::ComPtr<IWindowsParentalControlsCore> parent_controls;
HRESULT hr = ::CoCreateInstance(__uuidof(WindowsParentalControls), nullptr,
CLSCTX_ALL, IID_PPV_ARGS(&parent_controls));
if (FAILED(hr))
return WinParentalControls();
Microsoft::WRL::ComPtr<IWPCSettings> settings;
hr = parent_controls->GetUserSettings(nullptr, &settings);
if (FAILED(hr))
return WinParentalControls();
DWORD restrictions = 0;
settings->GetRestrictions(&restrictions);
WinParentalControls controls = {
restrictions != WPCFLAG_NO_RESTRICTION /* any_restrictions */,
(restrictions & WPCFLAG_LOGGING_REQUIRED) == WPCFLAG_LOGGING_REQUIRED
/* logging_required */,
(restrictions & WPCFLAG_WEB_FILTERED) == WPCFLAG_WEB_FILTERED
/* web_filter */
};
return controls;
}
// Update |controls| with parental controls found to be active by reading
// parental controls configuration from the registry. May be necessary on
// Win10 where the APIs are not fully supported and may not always accurately
// report such state.
//
// TODO(ericorth@chromium.org): Detect |logging_required| configuration,
// rather than just web filtering.
static void UpdateParentalControlsFromRegistry(
WinParentalControls* controls) {
DCHECK(controls);
std::wstring user_sid;
if (!base::win::GetUserSidString(&user_sid))
return;
static constexpr wchar_t kWebFilterRegistryPathFormat[] =
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Parental "
"Controls\\Users\\%ls\\Web";
std::wstring web_filter_key_path =
base::StringPrintf(kWebFilterRegistryPathFormat, user_sid.c_str());
base::win::RegKey web_filter_key(
HKEY_LOCAL_MACHINE, web_filter_key_path.c_str(), KEY_QUERY_VALUE);
if (!web_filter_key.Valid())
return;
// Web filtering is in use if the key contains any non-zero "Filter On"
// value.
DWORD filter_on_value;
if (web_filter_key.ReadValueDW(L"Filter On", &filter_on_value) ==
ERROR_SUCCESS &&
filter_on_value) {
controls->any_restrictions = true;
controls->web_filter = true;
}
}
static WinParentalControls GetParentalControls() {
WinParentalControls controls = GetParentalControlsFromApi();
// Parental controls APIs are not fully supported in Win10 and beyond, so
// check registry properties for restictions.
UpdateParentalControlsFromRegistry(&controls);
return controls;
}
const WinParentalControls parental_controls_;
};
} // namespace
void InitializeWinParentalControls() {
base::ThreadPool::CreateCOMSTATaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE})
->PostTask(FROM_HERE, base::BindOnce(base::IgnoreResult(
&WinParentalControlsValue::GetInstance)));
}
const WinParentalControls& GetWinParentalControls() {
return WinParentalControlsValue::GetInstance()->parental_controls();
}