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 "chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/logging.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
14 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
15 #include "chrome/browser/chromeos/policy/server_backed_state_keys_broker.h"
16 #include "chromeos/chromeos_switches.h"
17 #include "components/policy/core/common/cloud/device_management_service.h"
18 #include "net/url_request/url_request_context_getter.h"
19
20 namespace chromeos {
21
22 namespace {
23
24 // Returns the int value of the |switch_name| argument, clamped to the [0, 62]
25 // interval. Returns 0 if the argument doesn't exist or isn't an int value.
GetSanitizedArg(const std::string & switch_name)26 int GetSanitizedArg(const std::string& switch_name) {
27 CommandLine* command_line = CommandLine::ForCurrentProcess();
28 if (!command_line->HasSwitch(switch_name))
29 return 0;
30 std::string value = command_line->GetSwitchValueASCII(switch_name);
31 int int_value;
32 if (!base::StringToInt(value, &int_value)) {
33 LOG(ERROR) << "Switch \"" << switch_name << "\" is not a valid int. "
34 << "Defaulting to 0.";
35 return 0;
36 }
37 if (int_value < 0) {
38 LOG(ERROR) << "Switch \"" << switch_name << "\" can't be negative. "
39 << "Using 0";
40 return 0;
41 }
42 if (int_value > policy::AutoEnrollmentClient::kMaximumPower) {
43 LOG(ERROR) << "Switch \"" << switch_name << "\" can't be greater than "
44 << policy::AutoEnrollmentClient::kMaximumPower << ". Using "
45 << policy::AutoEnrollmentClient::kMaximumPower;
46 return policy::AutoEnrollmentClient::kMaximumPower;
47 }
48 return int_value;
49 }
50
51 } // namespace
52
53 const char AutoEnrollmentController::kForcedReEnrollmentAlways[] = "always";
54 const char AutoEnrollmentController::kForcedReEnrollmentLegacy[] = "legacy";
55 const char AutoEnrollmentController::kForcedReEnrollmentNever[] = "never";
56 const char AutoEnrollmentController::kForcedReEnrollmentOfficialBuild[] =
57 "official";
58
GetMode()59 AutoEnrollmentController::Mode AutoEnrollmentController::GetMode() {
60 CommandLine* command_line = CommandLine::ForCurrentProcess();
61
62 if (!command_line->HasSwitch(switches::kEnterpriseEnableForcedReEnrollment))
63 return MODE_LEGACY_AUTO_ENROLLMENT;
64
65 std::string command_line_mode = command_line->GetSwitchValueASCII(
66 switches::kEnterpriseEnableForcedReEnrollment);
67 if (command_line_mode == kForcedReEnrollmentAlways) {
68 return MODE_FORCED_RE_ENROLLMENT;
69 } else if (command_line_mode.empty() ||
70 command_line_mode == kForcedReEnrollmentOfficialBuild) {
71 #if defined(OFFICIAL_BUILD)
72 return MODE_FORCED_RE_ENROLLMENT;
73 #else
74 return MODE_NONE;
75 #endif
76 } else if (command_line_mode == kForcedReEnrollmentLegacy) {
77 return MODE_LEGACY_AUTO_ENROLLMENT;
78 }
79
80 return MODE_NONE;
81 }
82
AutoEnrollmentController()83 AutoEnrollmentController::AutoEnrollmentController()
84 : state_(policy::AUTO_ENROLLMENT_STATE_IDLE),
85 client_start_weak_factory_(this) {}
86
~AutoEnrollmentController()87 AutoEnrollmentController::~AutoEnrollmentController() {}
88
Start()89 void AutoEnrollmentController::Start() {
90 // This method is called at the point in the OOBE/login flow at which the
91 // auto-enrollment check can start. This happens either after the EULA is
92 // accepted, or right after a reboot if the EULA has already been accepted.
93
94 // Do not communicate auto-enrollment data to the server if
95 // 1. we are running integration or perf tests with telemetry.
96 // 2. modulus configuration is not present.
97 // 3. Auto-enrollment is disabled via the command line.
98
99 CommandLine* command_line = CommandLine::ForCurrentProcess();
100 if (command_line->HasSwitch(chromeos::switches::kOobeSkipPostLogin) ||
101 (!command_line->HasSwitch(
102 chromeos::switches::kEnterpriseEnrollmentInitialModulus) &&
103 !command_line->HasSwitch(
104 chromeos::switches::kEnterpriseEnrollmentModulusLimit)) ||
105 GetMode() == MODE_NONE) {
106 VLOG(1) << "Auto-enrollment disabled.";
107 UpdateState(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT);
108 return;
109 }
110
111 // If a client is being created or already existing, bail out.
112 if (client_start_weak_factory_.HasWeakPtrs() || client_)
113 return;
114
115 // Start by checking if the device has already been owned.
116 UpdateState(policy::AUTO_ENROLLMENT_STATE_PENDING);
117 DeviceSettingsService::Get()->GetOwnershipStatusAsync(
118 base::Bind(&AutoEnrollmentController::OnOwnershipStatusCheckDone,
119 client_start_weak_factory_.GetWeakPtr()));
120 }
121
Cancel()122 void AutoEnrollmentController::Cancel() {
123 if (client_) {
124 // Cancelling the |client_| allows it to determine whether
125 // its protocol finished before login was complete.
126 client_.release()->CancelAndDeleteSoon();
127 }
128
129 // Make sure to nuke pending |client_| start sequences.
130 client_start_weak_factory_.InvalidateWeakPtrs();
131 }
132
Retry()133 void AutoEnrollmentController::Retry() {
134 if (client_)
135 client_->Retry();
136 }
137
138 scoped_ptr<AutoEnrollmentController::ProgressCallbackList::Subscription>
RegisterProgressCallback(const ProgressCallbackList::CallbackType & callback)139 AutoEnrollmentController::RegisterProgressCallback(
140 const ProgressCallbackList::CallbackType& callback) {
141 return progress_callbacks_.Add(callback);
142 }
143
ShouldEnrollSilently()144 bool AutoEnrollmentController::ShouldEnrollSilently() {
145 return state_ == policy::AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT &&
146 GetMode() == MODE_LEGACY_AUTO_ENROLLMENT;
147 }
148
OnOwnershipStatusCheckDone(DeviceSettingsService::OwnershipStatus status)149 void AutoEnrollmentController::OnOwnershipStatusCheckDone(
150 DeviceSettingsService::OwnershipStatus status) {
151 if (status != DeviceSettingsService::OWNERSHIP_NONE) {
152 // The device is already owned. No need for auto-enrollment checks.
153 VLOG(1) << "Device already owned, skipping auto-enrollment check";
154 UpdateState(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT);
155 return;
156 }
157
158 // Make sure state keys are available.
159 g_browser_process->platform_part()
160 ->browser_policy_connector_chromeos()
161 ->GetStateKeysBroker()
162 ->RequestStateKeys(base::Bind(&AutoEnrollmentController::StartClient,
163 client_start_weak_factory_.GetWeakPtr()));
164 }
165
StartClient(const std::vector<std::string> & state_keys)166 void AutoEnrollmentController::StartClient(
167 const std::vector<std::string>& state_keys) {
168 policy::BrowserPolicyConnectorChromeOS* connector =
169 g_browser_process->platform_part()->browser_policy_connector_chromeos();
170 policy::DeviceManagementService* service =
171 connector->device_management_service();
172 service->ScheduleInitialization(0);
173
174 int power_initial = GetSanitizedArg(
175 chromeos::switches::kEnterpriseEnrollmentInitialModulus);
176 int power_limit = GetSanitizedArg(
177 chromeos::switches::kEnterpriseEnrollmentModulusLimit);
178 if (power_initial > power_limit) {
179 LOG(ERROR) << "Initial auto-enrollment modulus is larger than the limit, "
180 << "clamping to the limit.";
181 power_initial = power_limit;
182 }
183
184 bool retrieve_device_state = false;
185 std::string device_id;
186 if (GetMode() == MODE_FORCED_RE_ENROLLMENT) {
187 retrieve_device_state = true;
188 device_id = state_keys.empty() ? std::string() : state_keys.front();
189 } else {
190 device_id = policy::DeviceCloudPolicyManagerChromeOS::GetMachineID();
191 }
192
193 client_.reset(new policy::AutoEnrollmentClient(
194 base::Bind(&AutoEnrollmentController::UpdateState,
195 base::Unretained(this)),
196 service,
197 g_browser_process->local_state(),
198 g_browser_process->system_request_context(),
199 device_id,
200 retrieve_device_state,
201 power_initial,
202 power_limit));
203
204 VLOG(1) << "Starting auto-enrollment client.";
205 client_->Start();
206 }
207
UpdateState(policy::AutoEnrollmentState new_state)208 void AutoEnrollmentController::UpdateState(
209 policy::AutoEnrollmentState new_state) {
210 state_ = new_state;
211 progress_callbacks_.Notify(state_);
212 }
213
214 } // namespace chromeos
215