auto_enrollment_controller.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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
20namespace chromeos {
21
22namespace {
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.
26int 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
53const char AutoEnrollmentController::kForcedReEnrollmentAlways[] = "always";
54const char AutoEnrollmentController::kForcedReEnrollmentLegacy[] = "legacy";
55const char AutoEnrollmentController::kForcedReEnrollmentNever[] = "never";
56const char AutoEnrollmentController::kForcedReEnrollmentOfficialBuild[] =
57    "official";
58
59AutoEnrollmentController::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
83AutoEnrollmentController::AutoEnrollmentController()
84    : state_(policy::AUTO_ENROLLMENT_STATE_IDLE),
85      client_start_weak_factory_(this) {}
86
87AutoEnrollmentController::~AutoEnrollmentController() {}
88
89void 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 telemetry tests.
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::kDisableGaiaServices) ||
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
122void 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
133void AutoEnrollmentController::Retry() {
134  if (client_)
135    client_->Retry();
136}
137
138scoped_ptr<AutoEnrollmentController::ProgressCallbackList::Subscription>
139AutoEnrollmentController::RegisterProgressCallback(
140    const ProgressCallbackList::CallbackType& callback) {
141  return progress_callbacks_.Add(callback);
142}
143
144bool AutoEnrollmentController::ShouldEnrollSilently() {
145  return state_ == policy::AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT &&
146         GetMode() == MODE_LEGACY_AUTO_ENROLLMENT;
147}
148
149void 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
166void 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
208void AutoEnrollmentController::UpdateState(
209    policy::AutoEnrollmentState new_state) {
210  VLOG(1) << "New state: " << new_state << ".";
211  state_ = new_state;
212  progress_callbacks_.Notify(state_);
213}
214
215}  // namespace chromeos
216