auto_enrollment_client.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
19720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// Copyright (c) 2012 The Chromium Authors. All rights reserved. 29720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// Use of this source code is governed by a BSD-style license that can be 39720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// found in the LICENSE file. 49720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 59720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "chrome/browser/chromeos/policy/auto_enrollment_client.h" 69720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 79720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "base/bind.h" 89720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "base/command_line.h" 99720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "base/guid.h" 109720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "base/location.h" 119720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "base/logging.h" 129720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "base/message_loop_proxy.h" 139720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "base/metrics/histogram.h" 149720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "base/prefs/pref_registry_simple.h" 159720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "base/prefs/pref_service.h" 169720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "base/strings/string_number_conversions.h" 179720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "chrome/browser/browser_process.h" 189720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" 199720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "chrome/browser/policy/browser_policy_connector.h" 209720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "chrome/browser/policy/cloud/device_management_service.h" 219720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "chrome/common/chrome_switches.h" 229720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "chrome/common/pref_names.h" 239720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block#include "crypto/sha2.h" 249720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 259720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blocknamespace em = enterprise_management; 269720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 279720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blocknamespace { 289720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 299720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// The modulus value is sent in an int64 field in the protobuf, whose maximum 309720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// value is 2^63-1. So 2^64 and 2^63 can't be represented as moduli and the 319720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// max is 2^62 (when the moduli are restricted to powers-of-2). 329720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockconst int kMaximumPower = 62; 339720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 349720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// Returns the int value of the |switch_name| argument, clamped to the [0, 62] 359720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// interval. Returns 0 if the argument doesn't exist or isn't an int value. 369720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockint GetSanitizedArg(const std::string& switch_name) { 379720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block CommandLine* command_line = CommandLine::ForCurrentProcess(); 389720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (!command_line->HasSwitch(switch_name)) 399720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return 0; 409720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block std::string value = command_line->GetSwitchValueASCII(switch_name); 419720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block int int_value; 429720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (!base::StringToInt(value, &int_value)) { 439720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block LOG(ERROR) << "Switch \"" << switch_name << "\" is not a valid int. " 449720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block << "Defaulting to 0."; 459720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return 0; 469720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 479720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (int_value < 0) { 489720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block LOG(ERROR) << "Switch \"" << switch_name << "\" can't be negative. " 499720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block << "Using 0"; 509720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return 0; 519720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 529720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (int_value > kMaximumPower) { 539720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block LOG(ERROR) << "Switch \"" << switch_name << "\" can't be greater than " 549720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block << kMaximumPower << ". Using " << kMaximumPower; 559720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return kMaximumPower; 569720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 579720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return int_value; 589720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block} 599720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 609720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// Returns the power of the next power-of-2 starting at |value|. 619720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockint NextPowerOf2(int64 value) { 629720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block for (int i = 0; i <= kMaximumPower; ++i) { 639720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if ((GG_INT64_C(1) << i) >= value) 649720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return i; 65a721beb6d7372334152406a36e8db016650a9691Tareq A. Siraj } 66a721beb6d7372334152406a36e8db016650a9691Tareq A. Siraj // No other value can be represented in an int64. 67a721beb6d7372334152406a36e8db016650a9691Tareq A. Siraj return kMaximumPower + 1; 68a721beb6d7372334152406a36e8db016650a9691Tareq A. Siraj} 69a721beb6d7372334152406a36e8db016650a9691Tareq A. Siraj 70a721beb6d7372334152406a36e8db016650a9691Tareq A. Siraj} // namespace 719720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 729720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blocknamespace policy { 739720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 749720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve BlockAutoEnrollmentClient::AutoEnrollmentClient(const base::Closure& callback, 759720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block DeviceManagementService* service, 769720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block PrefService* local_state, 779720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block const std::string& serial_number, 789720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block int power_initial, 799720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block int power_limit) 809720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block : completion_callback_(callback), 819720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block should_auto_enroll_(false), 829720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block device_id_(base::GenerateGUID()), 839720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block power_initial_(power_initial), 84e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott power_limit_(power_limit), 859720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block requests_sent_(0), 869720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block device_management_service_(service), 879720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block local_state_(local_state) { 889720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block DCHECK_LE(power_initial_, power_limit_); 899720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (!serial_number.empty()) 909720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block serial_number_hash_ = crypto::SHA256HashString(serial_number); 919720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block} 929720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 939720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve BlockAutoEnrollmentClient::~AutoEnrollmentClient() {} 949720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 959720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// static 969720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockvoid AutoEnrollmentClient::RegisterPrefs(PrefRegistrySimple* registry) { 979720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block registry->RegisterBooleanPref(prefs::kShouldAutoEnroll, false); 989720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block registry->RegisterIntegerPref(prefs::kAutoEnrollmentPowerLimit, -1); 999720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block} 1009720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 1019720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// static 1029720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockbool AutoEnrollmentClient::IsDisabled() { 1039720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block CommandLine* command_line = CommandLine::ForCurrentProcess(); 1049720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return 1059720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block !command_line->HasSwitch(switches::kEnterpriseEnrollmentInitialModulus) && 1069720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block !command_line->HasSwitch(switches::kEnterpriseEnrollmentModulusLimit); 1079720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block} 1089720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 1099720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// static 1109720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve BlockAutoEnrollmentClient* AutoEnrollmentClient::Create( 1119720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block const base::Closure& completion_callback) { 1129720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // The client won't do anything if |service| is NULL. 1139720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block DeviceManagementService* service = NULL; 1149720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (IsDisabled()) { 1159720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block VLOG(1) << "Auto-enrollment is disabled"; 1169720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } else { 1179720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block std::string url = BrowserPolicyConnector::GetDeviceManagementUrl(); 1189720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (!url.empty()) { 1199720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block service = new DeviceManagementService(url); 1209720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block service->ScheduleInitialization(0); 1219720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 1229720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 1239720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 1249720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block int power_initial = GetSanitizedArg( 1259720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block switches::kEnterpriseEnrollmentInitialModulus); 1269720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block int power_limit = GetSanitizedArg( 1279720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block switches::kEnterpriseEnrollmentModulusLimit); 1289720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (power_initial > power_limit) { 1299720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block LOG(ERROR) << "Initial auto-enrollment modulus is larger than the limit, " 1309720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block << "clamping to the limit."; 1319720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block power_initial = power_limit; 1329720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 1339720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 1349720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return new AutoEnrollmentClient( 1359720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block completion_callback, 1369720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block service, 1379720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block g_browser_process->local_state(), 1389720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block DeviceCloudPolicyManagerChromeOS::GetMachineID(), 1399720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block power_initial, 1409720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block power_limit); 1419720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block} 1429720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 1439720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// static 1449720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockvoid AutoEnrollmentClient::CancelAutoEnrollment() { 1459720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block PrefService* local_state = g_browser_process->local_state(); 1469720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block local_state->SetBoolean(prefs::kShouldAutoEnroll, false); 1479720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block local_state->CommitPendingWrite(); 148e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott} 149e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott 150e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scottvoid AutoEnrollmentClient::Start() { 151e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott // Drop the previous job and reset state. 152e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott request_job_.reset(); 153e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott should_auto_enroll_ = false; 154e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott time_start_ = base::Time(); // reset to null. 155e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott 156e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott if (GetCachedDecision()) { 157e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott VLOG(1) << "AutoEnrollmentClient: using cached decision: " 1589720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block << should_auto_enroll_; 1599720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } else if (device_management_service_.get()) { 1609720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (serial_number_hash_.empty()) { 1619720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block LOG(ERROR) << "Failed to get the hash of the serial number, " 1629720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block << "will not attempt to auto-enroll."; 1639720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } else { 1649720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block time_start_ = base::Time::Now(); 1659720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block SendRequest(power_initial_); 1669720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // Don't invoke the callback now. 1679720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return; 1689720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 1699720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 1709720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 17189f07d6a92dab765c534266a640933ebd2f6d9e4Chris Dearman // Auto-enrollment can't even start, so we're done. 1729720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block OnProtocolDone(); 1739720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block} 1749720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 1759720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockvoid AutoEnrollmentClient::CancelAndDeleteSoon() { 1769720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (time_start_.is_null()) { 1779720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // The client isn't running, just delete it. 1789720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block delete this; 1799720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } else { 1809720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // Client still running, but our owner isn't interested in the result 1819720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // anymore. Wait until the protocol completes to measure the extra time 1829720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // needed. 1839720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block time_extra_start_ = base::Time::Now(); 1849720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block completion_callback_.Reset(); 1859720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 1869720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block} 1879720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 1889720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockbool AutoEnrollmentClient::GetCachedDecision() { 1899720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block const PrefService::Preference* should_enroll_pref = 1909720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block local_state_->FindPreference(prefs::kShouldAutoEnroll); 1919720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block const PrefService::Preference* previous_limit_pref = 1929720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block local_state_->FindPreference(prefs::kAutoEnrollmentPowerLimit); 1939720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block bool should_auto_enroll = false; 1949720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block int previous_limit = -1; 1959720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 1969720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (!should_enroll_pref || 1979720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block should_enroll_pref->IsDefaultValue() || 1989720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block !should_enroll_pref->GetValue()->GetAsBoolean(&should_auto_enroll) || 1999720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block !previous_limit_pref || 2009720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block previous_limit_pref->IsDefaultValue() || 2019720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block !previous_limit_pref->GetValue()->GetAsInteger(&previous_limit) || 2029720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block power_limit_ > previous_limit) { 2039720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return false; 2049720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 2059720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 2069720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block should_auto_enroll_ = should_auto_enroll; 2079720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return true; 2089720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block} 2099720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 2109720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockvoid AutoEnrollmentClient::SendRequest(int power) { 211e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott if (power < 0 || power > power_limit_ || serial_number_hash_.empty()) { 212e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott NOTREACHED(); 2139720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block OnProtocolDone(); 2149720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return; 2159720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 2169720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 2179720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block requests_sent_++; 2189720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 2199720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // Only power-of-2 moduli are supported for now. These are computed by taking 2209720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // the lower |power| bits of the hash. 2219720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block uint64 remainder = 0; 2229720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block for (int i = 0; 8 * i < power; ++i) { 223e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott uint64 byte = serial_number_hash_[31 - i] & 0xff; 224e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott remainder = remainder | (byte << (8 * i)); 225e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott } 2269720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block remainder = remainder & ((GG_UINT64_C(1) << power) - 1); 2279720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 2289720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block request_job_.reset( 2299720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block device_management_service_->CreateJob( 2309720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block DeviceManagementRequestJob::TYPE_AUTO_ENROLLMENT)); 2319720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block request_job_->SetClientID(device_id_); 2329720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block em::DeviceAutoEnrollmentRequest* request = 2339720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block request_job_->GetRequest()->mutable_auto_enrollment_request(); 2349720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block request->set_remainder(remainder); 2359720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block request->set_modulus(GG_INT64_C(1) << power); 2369720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block request_job_->Start(base::Bind(&AutoEnrollmentClient::OnRequestCompletion, 2379720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block base::Unretained(this))); 2389720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block} 2399720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 2409720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockvoid AutoEnrollmentClient::OnRequestCompletion( 2419720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block DeviceManagementStatus status, 2429720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block const em::DeviceManagementResponse& response) { 2439720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (status != DM_STATUS_SUCCESS || !response.has_auto_enrollment_response()) { 2449720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block LOG(ERROR) << "Auto enrollment error: " << status; 2459720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block OnProtocolDone(); 2469720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return; 2479720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 2489720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 2499720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block const em::DeviceAutoEnrollmentResponse& enrollment_response = 2509720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block response.auto_enrollment_response(); 2519720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (enrollment_response.has_expected_modulus()) { 2529720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // Server is asking us to retry with a different modulus. 2539720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block int64 modulus = enrollment_response.expected_modulus(); 2549720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block int power = NextPowerOf2(modulus); 255e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott if ((GG_INT64_C(1) << power) != modulus) { 2569720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block LOG(WARNING) << "Auto enrollment: the server didn't ask for a power-of-2 " 2579720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block << "modulus. Using the closest power-of-2 instead " 2589720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block << "(" << modulus << " vs 2^" << power << ")"; 2599720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 2609720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (requests_sent_ >= 2) { 2619720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block LOG(ERROR) << "Auto enrollment error: already retried with an updated " 2629720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block << "modulus but the server asked for a new one again: " 2639720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block << power; 2649720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } else if (power > power_limit_) { 2659720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block LOG(ERROR) << "Auto enrollment error: the server asked for a larger " 266e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott << "modulus than the client accepts (" << power << " vs " 2679720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block << power_limit_ << ")."; 2689720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } else { 2699720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // Retry at most once with the modulus that the server requested. 2709720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (power <= power_initial_) { 2719720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block LOG(WARNING) << "Auto enrollment: the server asked to use a modulus (" 2729720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block << power << ") that isn't larger than the first used (" 2739720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block << power_initial_ << "). Retrying anyway."; 2749720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 2759720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block SendRequest(power); 2769720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // Don't invoke the callback yet. 2779720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return; 2789720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 2799720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } else { 2809720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // Server should have sent down a list of hashes to try. 2819720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block should_auto_enroll_ = IsSerialInProtobuf(enrollment_response.hash()); 2829720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block LOG(INFO) << "Auto enrollment complete, should_auto_enroll = " 2839720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block << should_auto_enroll_; 2849720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 2859720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 2869720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // Auto-enrollment done. 2879720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block OnProtocolDone(); 2889720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block} 2899720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 2909720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockbool AutoEnrollmentClient::IsSerialInProtobuf( 2919720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block const google::protobuf::RepeatedPtrField<std::string>& hashes) { 2929720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block for (int i = 0; i < hashes.size(); ++i) { 2939720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (hashes.Get(i) == serial_number_hash_) 2949720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return true; 2959720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 2969720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block return false; 297e46c9386c4f79aa40185f79a19fc5b2a7ef528b3Patrick Scott} 2989720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 2999720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockvoid AutoEnrollmentClient::OnProtocolDone() { 3009720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block static const char* kProtocolTime = "Enterprise.AutoEnrollmentProtocolTime"; 3019720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block static const char* kExtraTime = "Enterprise.AutoEnrollmentExtraTime"; 3029720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // The mininum time can't be 0, must be at least 1. 3039720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block static const base::TimeDelta kMin = base::TimeDelta::FromMilliseconds(1); 3049720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block static const base::TimeDelta kMax = base::TimeDelta::FromMinutes(5); 3059720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // However, 0 can still be sampled. 3069720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block static const base::TimeDelta kZero = base::TimeDelta::FromMilliseconds(0); 3079720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block static const int kBuckets = 50; 3089720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 3099720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block base::Time now = base::Time::Now(); 3109720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (!time_start_.is_null()) { 3119720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block base::TimeDelta delta = now - time_start_; 3129720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block UMA_HISTOGRAM_CUSTOM_TIMES(kProtocolTime, delta, kMin, kMax, kBuckets); 3139720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block time_start_ = base::Time(); 3149720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 3159720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // The decision is cached only if the protocol was actually started, which 3169720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // is the case only if |time_start_| was not null. 3179720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block local_state_->SetBoolean(prefs::kShouldAutoEnroll, should_auto_enroll_); 3189720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block local_state_->SetInteger(prefs::kAutoEnrollmentPowerLimit, power_limit_); 3199720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block local_state_->CommitPendingWrite(); 3209720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 3219720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block base::TimeDelta delta = kZero; 3229720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (!time_extra_start_.is_null()) { 3239720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // CancelAndDeleteSoon() was invoked before. 3249720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block delta = now - time_extra_start_; 3259720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, this); 3269720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block time_extra_start_ = base::Time(); 3279720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 3289720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // This samples |kZero| when there was no need for extra time, so that we can 3299720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // measure the ratio of users that succeeded without needing a delay to the 3309720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // total users going through OOBE. 3319720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block UMA_HISTOGRAM_CUSTOM_TIMES(kExtraTime, delta, kMin, kMax, kBuckets); 3329720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 3339720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block if (!completion_callback_.is_null()) 3349720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block completion_callback_.Run(); 3359720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block} 3369720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 3379720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block} // namespace policy 3389720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block