auto_enrollment_client.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/policy/auto_enrollment_client.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/guid.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 12b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 14b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/metrics/sparse_histogram.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_registry_simple.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/policy/browser_policy_connector.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/policy/cloud/device_management_service.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h" 23b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chromeos/chromeos_switches.h" 2468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/sha2.h" 2668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h" 2768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 2868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)using content::BrowserThread; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace em = enterprise_management; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// UMA histogram names. 35b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char kUMAProtocolTime[] = "Enterprise.AutoEnrollmentProtocolTime"; 36b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char kUMAExtraTime[] = "Enterprise.AutoEnrollmentExtraTime"; 37b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char kUMARequestStatus[] = "Enterprise.AutoEnrollmentRequestStatus"; 38b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char kUMANetworkErrorCode[] = 39b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) "Enterprise.AutoEnrollmentRequestNetworkErrorCode"; 40b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The modulus value is sent in an int64 field in the protobuf, whose maximum 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// value is 2^63-1. So 2^64 and 2^63 can't be represented as moduli and the 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// max is 2^62 (when the moduli are restricted to powers-of-2). 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaximumPower = 62; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the int value of the |switch_name| argument, clamped to the [0, 62] 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// interval. Returns 0 if the argument doesn't exist or isn't an int value. 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int GetSanitizedArg(const std::string& switch_name) { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandLine* command_line = CommandLine::ForCurrentProcess(); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!command_line->HasSwitch(switch_name)) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string value = command_line->GetSwitchValueASCII(switch_name); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int int_value; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::StringToInt(value, &int_value)) { 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Switch \"" << switch_name << "\" is not a valid int. " 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Defaulting to 0."; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (int_value < 0) { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Switch \"" << switch_name << "\" can't be negative. " 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Using 0"; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (int_value > kMaximumPower) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Switch \"" << switch_name << "\" can't be greater than " 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << kMaximumPower << ". Using " << kMaximumPower; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return kMaximumPower; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return int_value; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the power of the next power-of-2 starting at |value|. 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int NextPowerOf2(int64 value) { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i <= kMaximumPower; ++i) { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((GG_INT64_C(1) << i) >= value) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return i; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No other value can be represented in an int64. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return kMaximumPower + 1; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace policy { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AutoEnrollmentClient::AutoEnrollmentClient(const base::Closure& callback, 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeviceManagementService* service, 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrefService* local_state, 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& serial_number, 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int power_initial, 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int power_limit) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : completion_callback_(callback), 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_auto_enroll_(false), 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_id_(base::GenerateGUID()), 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) power_initial_(power_initial), 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) power_limit_(power_limit), 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) requests_sent_(0), 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_management_service_(service), 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local_state_(local_state) { 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LE(power_initial_, power_limit_); 101bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DCHECK(!completion_callback_.is_null()); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!serial_number.empty()) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) serial_number_hash_ = crypto::SHA256HashString(serial_number); 104bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch net::NetworkChangeNotifier::AddNetworkChangeObserver(this); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 107bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochAutoEnrollmentClient::~AutoEnrollmentClient() { 108bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); 109bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch} 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutoEnrollmentClient::RegisterPrefs(PrefRegistrySimple* registry) { 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) registry->RegisterBooleanPref(prefs::kShouldAutoEnroll, false); 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) registry->RegisterIntegerPref(prefs::kAutoEnrollmentPowerLimit, -1); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AutoEnrollmentClient::IsDisabled() { 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandLine* command_line = CommandLine::ForCurrentProcess(); 120b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return !command_line->HasSwitch( 121b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) chromeos::switches::kEnterpriseEnrollmentInitialModulus) && 122b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) !command_line->HasSwitch( 123b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) chromeos::switches::kEnterpriseEnrollmentModulusLimit); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AutoEnrollmentClient* AutoEnrollmentClient::Create( 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::Closure& completion_callback) { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The client won't do anything if |service| is NULL. 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeviceManagementService* service = NULL; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsDisabled()) { 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "Auto-enrollment is disabled"; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string url = BrowserPolicyConnector::GetDeviceManagementUrl(); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!url.empty()) { 13668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) service = new DeviceManagementService( 13768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) g_browser_process->system_request_context(), 13868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) url); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) service->ScheduleInitialization(0); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int power_initial = GetSanitizedArg( 144b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) chromeos::switches::kEnterpriseEnrollmentInitialModulus); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int power_limit = GetSanitizedArg( 146b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) chromeos::switches::kEnterpriseEnrollmentModulusLimit); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (power_initial > power_limit) { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Initial auto-enrollment modulus is larger than the limit, " 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "clamping to the limit."; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) power_initial = power_limit; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new AutoEnrollmentClient( 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) completion_callback, 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) service, 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_browser_process->local_state(), 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeviceCloudPolicyManagerChromeOS::GetMachineID(), 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) power_initial, 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) power_limit); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AutoEnrollmentClient::CancelAutoEnrollment() { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrefService* local_state = g_browser_process->local_state(); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local_state->SetBoolean(prefs::kShouldAutoEnroll, false); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local_state->CommitPendingWrite(); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AutoEnrollmentClient::Start() { 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Drop the previous job and reset state. 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_job_.reset(); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_auto_enroll_ = false; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_start_ = base::Time(); // reset to null. 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetCachedDecision()) { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "AutoEnrollmentClient: using cached decision: " 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << should_auto_enroll_; 178bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } else if (device_management_service_) { 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (serial_number_hash_.empty()) { 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to get the hash of the serial number, " 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "will not attempt to auto-enroll."; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_start_ = base::Time::Now(); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendRequest(power_initial_); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't invoke the callback now. 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Auto-enrollment can't even start, so we're done. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnProtocolDone(); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AutoEnrollmentClient::CancelAndDeleteSoon() { 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (time_start_.is_null()) { 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The client isn't running, just delete it. 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete this; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Client still running, but our owner isn't interested in the result 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // anymore. Wait until the protocol completes to measure the extra time 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // needed. 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_extra_start_ = base::Time::Now(); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) completion_callback_.Reset(); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 207bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid AutoEnrollmentClient::OnNetworkChanged( 208bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch net::NetworkChangeNotifier::ConnectionType type) { 209bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (GetCachedDecision()) { 210bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // A previous request already obtained a definitive response from the 211bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // server, so there is no point in retrying; it will get the same decision. 212bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return; 213bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } 214bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 215bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (type != net::NetworkChangeNotifier::CONNECTION_NONE && 216bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch !completion_callback_.is_null() && 217bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch !request_job_ && 218bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch device_management_service_ && 219bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch !serial_number_hash_.empty()) { 220bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch VLOG(1) << "Retrying auto enrollment check after network changed"; 221bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch time_start_ = base::Time::Now(); 222bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch SendRequest(power_initial_); 223bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } 224bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch} 225bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AutoEnrollmentClient::GetCachedDecision() { 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PrefService::Preference* should_enroll_pref = 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local_state_->FindPreference(prefs::kShouldAutoEnroll); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PrefService::Preference* previous_limit_pref = 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local_state_->FindPreference(prefs::kAutoEnrollmentPowerLimit); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool should_auto_enroll = false; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int previous_limit = -1; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!should_enroll_pref || 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_enroll_pref->IsDefaultValue() || 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !should_enroll_pref->GetValue()->GetAsBoolean(&should_auto_enroll) || 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !previous_limit_pref || 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) previous_limit_pref->IsDefaultValue() || 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !previous_limit_pref->GetValue()->GetAsInteger(&previous_limit) || 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) power_limit_ > previous_limit) { 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_auto_enroll_ = should_auto_enroll; 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AutoEnrollmentClient::SendRequest(int power) { 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (power < 0 || power > power_limit_ || serial_number_hash_.empty()) { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 251bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch OnRequestDone(); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) requests_sent_++; 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only power-of-2 moduli are supported for now. These are computed by taking 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the lower |power| bits of the hash. 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 remainder = 0; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; 8 * i < power; ++i) { 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 byte = serial_number_hash_[31 - i] & 0xff; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) remainder = remainder | (byte << (8 * i)); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) remainder = remainder & ((GG_UINT64_C(1) << power) - 1); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_job_.reset( 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_management_service_->CreateJob( 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeviceManagementRequestJob::TYPE_AUTO_ENROLLMENT)); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_job_->SetClientID(device_id_); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) em::DeviceAutoEnrollmentRequest* request = 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_job_->GetRequest()->mutable_auto_enrollment_request(); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request->set_remainder(remainder); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request->set_modulus(GG_INT64_C(1) << power); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_job_->Start(base::Bind(&AutoEnrollmentClient::OnRequestCompletion, 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AutoEnrollmentClient::OnRequestCompletion( 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeviceManagementStatus status, 280b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) int net_error, 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const em::DeviceManagementResponse& response) { 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status != DM_STATUS_SUCCESS || !response.has_auto_enrollment_response()) { 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Auto enrollment error: " << status; 284b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) UMA_HISTOGRAM_SPARSE_SLOWLY(kUMARequestStatus, status); 285b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (status == DM_STATUS_REQUEST_FAILED) 286b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) UMA_HISTOGRAM_SPARSE_SLOWLY(kUMANetworkErrorCode, -net_error); 287bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // The client will retry if a network change is detected. 288bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch OnRequestDone(); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const em::DeviceAutoEnrollmentResponse& enrollment_response = 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response.auto_enrollment_response(); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (enrollment_response.has_expected_modulus()) { 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Server is asking us to retry with a different modulus. 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 modulus = enrollment_response.expected_modulus(); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int power = NextPowerOf2(modulus); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((GG_INT64_C(1) << power) != modulus) { 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(WARNING) << "Auto enrollment: the server didn't ask for a power-of-2 " 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "modulus. Using the closest power-of-2 instead " 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "(" << modulus << " vs 2^" << power << ")"; 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (requests_sent_ >= 2) { 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Auto enrollment error: already retried with an updated " 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "modulus but the server asked for a new one again: " 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << power; 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (power > power_limit_) { 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Auto enrollment error: the server asked for a larger " 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "modulus than the client accepts (" << power << " vs " 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << power_limit_ << ")."; 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Retry at most once with the modulus that the server requested. 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (power <= power_initial_) { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(WARNING) << "Auto enrollment: the server asked to use a modulus (" 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << power << ") that isn't larger than the first used (" 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << power_initial_ << "). Retrying anyway."; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 318bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // Remember this value, so that eventual retries start with the correct 319bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // modulus. 320bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch power_initial_ = power; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendRequest(power); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Server should have sent down a list of hashes to try. 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_auto_enroll_ = IsSerialInProtobuf(enrollment_response.hash()); 32790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Cache the current decision in local_state, so that it is reused in case 32890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // the device reboots before enrolling. 32990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) local_state_->SetBoolean(prefs::kShouldAutoEnroll, should_auto_enroll_); 33090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) local_state_->SetInteger(prefs::kAutoEnrollmentPowerLimit, power_limit_); 33190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) local_state_->CommitPendingWrite(); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "Auto enrollment complete, should_auto_enroll = " 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << should_auto_enroll_; 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Auto-enrollment done. 337b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) UMA_HISTOGRAM_SPARSE_SLOWLY(kUMARequestStatus, DM_STATUS_SUCCESS); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnProtocolDone(); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AutoEnrollmentClient::IsSerialInProtobuf( 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const google::protobuf::RepeatedPtrField<std::string>& hashes) { 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < hashes.size(); ++i) { 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (hashes.Get(i) == serial_number_hash_) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AutoEnrollmentClient::OnProtocolDone() { 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The mininum time can't be 0, must be at least 1. 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const base::TimeDelta kMin = base::TimeDelta::FromMilliseconds(1); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const base::TimeDelta kMax = base::TimeDelta::FromMinutes(5); 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // However, 0 can still be sampled. 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const base::TimeDelta kZero = base::TimeDelta::FromMilliseconds(0); 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kBuckets = 50; 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time now = base::Time::Now(); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!time_start_.is_null()) { 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta delta = now - time_start_; 361b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) UMA_HISTOGRAM_CUSTOM_TIMES(kUMAProtocolTime, delta, kMin, kMax, kBuckets); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta delta = kZero; 364bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (!time_extra_start_.is_null()) 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delta = now - time_extra_start_; 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This samples |kZero| when there was no need for extra time, so that we can 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // measure the ratio of users that succeeded without needing a delay to the 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // total users going through OOBE. 369b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) UMA_HISTOGRAM_CUSTOM_TIMES(kUMAExtraTime, delta, kMin, kMax, kBuckets); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!completion_callback_.is_null()) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) completion_callback_.Run(); 373bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 374bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch OnRequestDone(); 375bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch} 376bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 377bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid AutoEnrollmentClient::OnRequestDone() { 378bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch request_job_.reset(); 379bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch time_start_ = base::Time(); 380bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 381bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (completion_callback_.is_null()) { 382bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // CancelAndDeleteSoon() was invoked before. 383bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, this); 384bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace policy 388