File: parental_controls.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (160 lines) | stat: -rw-r--r-- 5,798 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// 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 <windows.h>

#include <combaseapi.h>
#include <winerror.h>
#include <wpcapi.h>
#include <wrl/client.h>

#include <string>

#include "base/check_is_test.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/strings/strcat_win.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 {

static bool g_has_called_initialize_win_parental_controls_ = false;

// 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() {
    // This call may block and be called from the UI thread, which is
    // unfortunate, but we want to at least make sure that we've attempted to
    // call InitializeWinParentalControls() in an attempt to load it early so
    // that we don't need to block.
    //
    // Note that this CHECK replaced a previous base::ScopedBlockingCall, which
    // was incorrect because there were no guarantees that
    // InitializeWinParentalControls() would finish executing asynchronously
    // before the value was needed. See https://crbug.com/1411815#c7.
    if (!g_has_called_initialize_win_parental_controls_) {
      // This uses CHECK_IS_TEST() to skip verifying that
      // InitializeWinParentalControls() got called in tests because updating
      // all test fixtures to call it seemed daunting.
      CHECK_IS_TEST();
    }
    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;

    std::wstring web_filter_key_path =
        base::StrCat({L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Parental "
                      L"Controls\\Users\\",
                      user_sid, L"\\Web"});
    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() {
  g_has_called_initialize_win_parental_controls_ = true;
  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();
}