1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/policy/core/browser/browser_policy_connector.h"
6 
7 #include <stddef.h>
8 #include <algorithm>
9 #include <utility>
10 #include <vector>
11 
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/logging.h"
15 #include "base/stl_util.h"
16 #include "base/strings/string16.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/threading/thread_task_runner_handle.h"
19 #include "base/trace_event/trace_event.h"
20 #include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h"
21 #include "components/policy/core/common/cloud/device_management_service.h"
22 #include "components/policy/core/common/configuration_policy_provider.h"
23 #include "components/policy/core/common/policy_namespace.h"
24 #include "components/policy/core/common/policy_pref_names.h"
25 #include "components/policy/core/common/policy_statistics_collector.h"
26 #include "components/policy/core/common/policy_switches.h"
27 #include "components/policy/policy_constants.h"
28 #include "components/prefs/pref_registry_simple.h"
29 #include "google_apis/gaia/gaia_auth_util.h"
30 #include "third_party/icu/source/i18n/unicode/regex.h"
31 
32 namespace policy {
33 
34 namespace {
35 
36 // The URL for the device management server.
37 const char kDefaultDeviceManagementServerUrl[] =
38     "https://m.google.com/devicemanagement/data/api";
39 
40 const char kDefaultEncryptedReportingServerUrl[] =
41     "https://chromereporting-pa.googleapis.com/v1/record";
42 
43 // The URL for the realtime reporting server.
44 const char kDefaultRealtimeReportingServerUrl[] =
45     "https://chromereporting-pa.googleapis.com/v1/events";
46 
47 // Regexes that match many of the larger public email providers as we know
48 // these users are not from hosted enterprise domains.
49 const wchar_t* const kNonManagedDomainPatterns[] = {
50   L"aol\\.com",
51   L"comcast\\.net",
52   L"googlemail\\.com",
53   L"gmail\\.com",
54   L"gmx\\.de",
55   L"hotmail(\\.co|\\.com|)\\.[^.]+",  // hotmail.com, hotmail.it, hotmail.co.uk
56   L"live\\.com",
57   L"mail\\.ru",
58   L"msn\\.com",
59   L"naver\\.com",
60   L"orange\\.fr",
61   L"outlook\\.com",
62   L"qq\\.com",
63   L"yahoo(\\.co|\\.com|)\\.[^.]+",  // yahoo.com, yahoo.co.uk, yahoo.com.tw
64   L"yandex\\.ru",
65   L"web\\.de",
66   L"wp\\.pl",
67   L"consumer\\.example\\.com",
68 };
69 
70 const char* non_managed_domain_for_testing = nullptr;
71 
72 // Returns true if |domain| matches the regex |pattern|.
MatchDomain(const base::string16 & domain,const base::string16 & pattern,size_t index)73 bool MatchDomain(const base::string16& domain, const base::string16& pattern,
74                  size_t index) {
75   UErrorCode status = U_ZERO_ERROR;
76   const icu::UnicodeString icu_pattern(pattern.data(), pattern.length());
77   icu::RegexMatcher matcher(icu_pattern, UREGEX_CASE_INSENSITIVE, status);
78   if (!U_SUCCESS(status)) {
79     // http://crbug.com/365351 - if for some reason the matcher creation fails
80     // just return that the pattern doesn't match the domain. This is safe
81     // because the calling method (IsNonEnterpriseUser()) is just used to enable
82     // an optimization for non-enterprise users - better to skip the
83     // optimization than crash.
84     DLOG(ERROR) << "Possible invalid domain pattern: " << pattern
85                 << " - Error: " << status;
86     return false;
87   }
88   icu::UnicodeString icu_input(domain.data(), domain.length());
89   matcher.reset(icu_input);
90   status = U_ZERO_ERROR;
91   UBool match = matcher.matches(status);
92   DCHECK(U_SUCCESS(status));
93   return !!match;  // !! == convert from UBool to bool.
94 }
95 
96 }  // namespace
97 
BrowserPolicyConnector(const HandlerListFactory & handler_list_factory)98 BrowserPolicyConnector::BrowserPolicyConnector(
99     const HandlerListFactory& handler_list_factory)
100     : BrowserPolicyConnectorBase(handler_list_factory) {
101 }
102 
~BrowserPolicyConnector()103 BrowserPolicyConnector::~BrowserPolicyConnector() {
104 }
105 
InitInternal(PrefService * local_state,std::unique_ptr<DeviceManagementService> device_management_service)106 void BrowserPolicyConnector::InitInternal(
107     PrefService* local_state,
108     std::unique_ptr<DeviceManagementService> device_management_service) {
109   device_management_service_ = std::move(device_management_service);
110 
111   policy_statistics_collector_.reset(new policy::PolicyStatisticsCollector(
112       base::BindRepeating(&GetChromePolicyDetails), GetChromeSchema(),
113       GetPolicyService(), local_state, base::ThreadTaskRunnerHandle::Get()));
114   policy_statistics_collector_->Initialize();
115 }
116 
Shutdown()117 void BrowserPolicyConnector::Shutdown() {
118   BrowserPolicyConnectorBase::Shutdown();
119   device_management_service_.reset();
120 }
121 
ScheduleServiceInitialization(int64_t delay_milliseconds)122 void BrowserPolicyConnector::ScheduleServiceInitialization(
123     int64_t delay_milliseconds) {
124   // Skip device initialization if the BrowserPolicyConnector was never
125   // initialized (unit tests).
126   if (device_management_service_)
127     device_management_service_->ScheduleInitialization(delay_milliseconds);
128 }
129 
ProviderHasPolicies(const ConfigurationPolicyProvider * provider) const130 bool BrowserPolicyConnector::ProviderHasPolicies(
131     const ConfigurationPolicyProvider* provider) const {
132   if (!provider)
133     return false;
134   for (const auto& pair : provider->policies()) {
135     if (!pair.second->empty())
136       return true;
137   }
138   return false;
139 }
140 
GetDeviceManagementUrl() const141 std::string BrowserPolicyConnector::GetDeviceManagementUrl() const {
142   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
143   if (command_line->HasSwitch(switches::kDeviceManagementUrl) &&
144       IsCommandLineSwitchSupported())
145     return command_line->GetSwitchValueASCII(switches::kDeviceManagementUrl);
146   else
147     return kDefaultDeviceManagementServerUrl;
148 }
149 
GetRealtimeReportingUrl() const150 std::string BrowserPolicyConnector::GetRealtimeReportingUrl() const {
151   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
152   if (command_line->HasSwitch(switches::kRealtimeReportingUrl) &&
153       IsCommandLineSwitchSupported())
154     return command_line->GetSwitchValueASCII(switches::kRealtimeReportingUrl);
155   else
156     return kDefaultRealtimeReportingServerUrl;
157 }
158 
GetEncryptedReportingUrl() const159 std::string BrowserPolicyConnector::GetEncryptedReportingUrl() const {
160   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
161   if (command_line->HasSwitch(switches::kEncryptedReportingUrl) &&
162       IsCommandLineSwitchSupported())
163     return command_line->GetSwitchValueASCII(switches::kEncryptedReportingUrl);
164   else
165     return kDefaultEncryptedReportingServerUrl;
166 }
167 
168 // static
IsNonEnterpriseUser(const std::string & username)169 bool BrowserPolicyConnector::IsNonEnterpriseUser(const std::string& username) {
170   TRACE_EVENT0("browser", "BrowserPolicyConnector::IsNonEnterpriseUser");
171   if (username.empty() || username.find('@') == std::string::npos) {
172     // An empty username means incognito user in case of ChromiumOS and
173     // no logged-in user in case of Chromium (SigninService). Many tests use
174     // nonsense email addresses (e.g. 'test') so treat those as non-enterprise
175     // users.
176     return true;
177   }
178   const base::string16 domain = base::UTF8ToUTF16(
179       gaia::ExtractDomainName(gaia::CanonicalizeEmail(username)));
180   for (size_t i = 0; i < base::size(kNonManagedDomainPatterns); i++) {
181     base::string16 pattern = base::WideToUTF16(kNonManagedDomainPatterns[i]);
182     if (MatchDomain(domain, pattern, i))
183       return true;
184   }
185   if (non_managed_domain_for_testing &&
186       domain == base::UTF8ToUTF16(non_managed_domain_for_testing)) {
187     return true;
188   }
189   return false;
190 }
191 
192 // static
SetNonEnterpriseDomainForTesting(const char * domain)193 void BrowserPolicyConnector::SetNonEnterpriseDomainForTesting(
194     const char* domain) {
195   non_managed_domain_for_testing = domain;
196 }
197 
198 // static
RegisterPrefs(PrefRegistrySimple * registry)199 void BrowserPolicyConnector::RegisterPrefs(PrefRegistrySimple* registry) {
200   registry->RegisterIntegerPref(
201       policy_prefs::kUserPolicyRefreshRate,
202       CloudPolicyRefreshScheduler::kDefaultRefreshDelayMs);
203   registry->RegisterBooleanPref(
204       policy_prefs::kCloudManagementEnrollmentMandatory, false);
205   registry->RegisterBooleanPref(
206       policy_prefs::kCloudPolicyOverridesPlatformPolicy, false);
207 }
208 
209 }  // namespace policy
210