• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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