Home | History | Annotate | Download | only in enrollment
      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.
     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 
     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 
     83 AutoEnrollmentController::AutoEnrollmentController()
     84     : state_(policy::AUTO_ENROLLMENT_STATE_IDLE),
     85       client_start_weak_factory_(this) {}
     86 
     87 AutoEnrollmentController::~AutoEnrollmentController() {}
     88 
     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 
    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 
    133 void AutoEnrollmentController::Retry() {
    134   if (client_)
    135     client_->Retry();
    136 }
    137 
    138 scoped_ptr<AutoEnrollmentController::ProgressCallbackList::Subscription>
    139 AutoEnrollmentController::RegisterProgressCallback(
    140     const ProgressCallbackList::CallbackType& callback) {
    141   return progress_callbacks_.Add(callback);
    142 }
    143 
    144 bool AutoEnrollmentController::ShouldEnrollSilently() {
    145   return state_ == policy::AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT &&
    146          GetMode() == MODE_LEGACY_AUTO_ENROLLMENT;
    147 }
    148 
    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 
    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 
    208 void AutoEnrollmentController::UpdateState(
    209     policy::AutoEnrollmentState new_state) {
    210   state_ = new_state;
    211   progress_callbacks_.Notify(state_);
    212 }
    213 
    214 }  // namespace chromeos
    215