enterprise_install_attributes.cc revision 3551c9c881056c480085172ff9840cab31610854
1// Copyright (c) 2012 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/policy/enterprise_install_attributes.h" 6 7#include <utility> 8 9#include "base/bind.h" 10#include "base/file_util.h" 11#include "base/location.h" 12#include "base/logging.h" 13#include "base/message_loop/message_loop.h" 14#include "chrome/browser/policy/proto/chromeos/install_attributes.pb.h" 15#include "chromeos/cryptohome/cryptohome_library.h" 16#include "chromeos/dbus/dbus_thread_manager.h" 17#include "google_apis/gaia/gaia_auth_util.h" 18 19namespace policy { 20 21namespace { 22 23// Translates DeviceMode constants to strings used in the lockbox. 24std::string GetDeviceModeString(DeviceMode mode) { 25 switch (mode) { 26 case DEVICE_MODE_CONSUMER: 27 return EnterpriseInstallAttributes::kConsumerDeviceMode; 28 case DEVICE_MODE_ENTERPRISE: 29 return EnterpriseInstallAttributes::kEnterpiseDeviceMode; 30 case DEVICE_MODE_RETAIL_KIOSK: 31 return EnterpriseInstallAttributes::kRetailKioskDeviceMode; 32 case DEVICE_MODE_CONSUMER_KIOSK: 33 return EnterpriseInstallAttributes::kConsumerKioskDeviceMode; 34 case DEVICE_MODE_PENDING: 35 case DEVICE_MODE_NOT_SET: 36 break; 37 } 38 NOTREACHED() << "Invalid device mode: " << mode; 39 return EnterpriseInstallAttributes::kUnknownDeviceMode; 40} 41 42// Translates strings used in the lockbox to DeviceMode values. 43DeviceMode GetDeviceModeFromString( 44 const std::string& mode) { 45 if (mode == EnterpriseInstallAttributes::kConsumerDeviceMode) 46 return DEVICE_MODE_CONSUMER; 47 else if (mode == EnterpriseInstallAttributes::kEnterpiseDeviceMode) 48 return DEVICE_MODE_ENTERPRISE; 49 else if (mode == EnterpriseInstallAttributes::kRetailKioskDeviceMode) 50 return DEVICE_MODE_RETAIL_KIOSK; 51 else if (mode == EnterpriseInstallAttributes::kConsumerKioskDeviceMode) 52 return DEVICE_MODE_CONSUMER_KIOSK; 53 NOTREACHED() << "Unknown device mode string: " << mode; 54 return DEVICE_MODE_NOT_SET; 55} 56 57bool ReadMapKey(const std::map<std::string, std::string>& map, 58 const std::string& key, 59 std::string* value) { 60 std::map<std::string, std::string>::const_iterator entry = map.find(key); 61 if (entry == map.end()) 62 return false; 63 64 *value = entry->second; 65 return true; 66} 67 68} // namespace 69 70const char EnterpriseInstallAttributes::kConsumerDeviceMode[] = "consumer"; 71const char EnterpriseInstallAttributes::kEnterpiseDeviceMode[] = "enterprise"; 72const char EnterpriseInstallAttributes::kRetailKioskDeviceMode[] = "kiosk"; 73const char EnterpriseInstallAttributes::kConsumerKioskDeviceMode[] = 74 "consumer_kiosk"; 75const char EnterpriseInstallAttributes::kUnknownDeviceMode[] = "unknown"; 76 77const char EnterpriseInstallAttributes::kAttrEnterpriseDeviceId[] = 78 "enterprise.device_id"; 79const char EnterpriseInstallAttributes::kAttrEnterpriseDomain[] = 80 "enterprise.domain"; 81const char EnterpriseInstallAttributes::kAttrEnterpriseMode[] = 82 "enterprise.mode"; 83const char EnterpriseInstallAttributes::kAttrEnterpriseOwned[] = 84 "enterprise.owned"; 85const char EnterpriseInstallAttributes::kAttrEnterpriseUser[] = 86 "enterprise.user"; 87const char EnterpriseInstallAttributes::kAttrConsumerKioskEnabled[] = 88 "consumer.app_kiosk_enabled"; 89 90EnterpriseInstallAttributes::EnterpriseInstallAttributes( 91 chromeos::CryptohomeLibrary* cryptohome, 92 chromeos::CryptohomeClient* cryptohome_client) 93 : device_locked_(false), 94 registration_mode_(DEVICE_MODE_PENDING), 95 cryptohome_(cryptohome), 96 cryptohome_client_(cryptohome_client), 97 weak_ptr_factory_(this) {} 98 99EnterpriseInstallAttributes::~EnterpriseInstallAttributes() {} 100 101void EnterpriseInstallAttributes::ReadCacheFile( 102 const base::FilePath& cache_file) { 103 if (device_locked_ || !base::PathExists(cache_file)) 104 return; 105 106 device_locked_ = true; 107 108 char buf[16384]; 109 int len = file_util::ReadFile(cache_file, buf, sizeof(buf)); 110 if (len == -1 || len >= static_cast<int>(sizeof(buf))) { 111 PLOG(ERROR) << "Failed to read " << cache_file.value(); 112 return; 113 } 114 115 cryptohome::SerializedInstallAttributes install_attrs_proto; 116 if (!install_attrs_proto.ParseFromArray(buf, len)) { 117 LOG(ERROR) << "Failed to parse install attributes cache"; 118 return; 119 } 120 121 google::protobuf::RepeatedPtrField< 122 const cryptohome::SerializedInstallAttributes::Attribute>::iterator entry; 123 std::map<std::string, std::string> attr_map; 124 for (entry = install_attrs_proto.attributes().begin(); 125 entry != install_attrs_proto.attributes().end(); 126 ++entry) { 127 // The protobuf values unfortunately contain terminating null characters, so 128 // we have to sanitize the value here. 129 attr_map.insert(std::make_pair(entry->name(), 130 std::string(entry->value().c_str()))); 131 } 132 133 DecodeInstallAttributes(attr_map); 134} 135 136void EnterpriseInstallAttributes::ReadImmutableAttributes( 137 const base::Closure& callback) { 138 if (device_locked_) { 139 callback.Run(); 140 return; 141 } 142 143 cryptohome_client_->InstallAttributesIsReady( 144 base::Bind(&EnterpriseInstallAttributes::ReadAttributesIfReady, 145 weak_ptr_factory_.GetWeakPtr(), 146 callback)); 147} 148 149void EnterpriseInstallAttributes::ReadAttributesIfReady( 150 const base::Closure& callback, 151 chromeos::DBusMethodCallStatus call_status, 152 bool result) { 153 if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS && result) { 154 registration_mode_ = DEVICE_MODE_NOT_SET; 155 if (!cryptohome_->InstallAttributesIsInvalid() && 156 !cryptohome_->InstallAttributesIsFirstInstall()) { 157 device_locked_ = true; 158 159 static const char* kEnterpriseAttributes[] = { 160 kAttrEnterpriseDeviceId, 161 kAttrEnterpriseDomain, 162 kAttrEnterpriseMode, 163 kAttrEnterpriseOwned, 164 kAttrEnterpriseUser, 165 kAttrConsumerKioskEnabled, 166 }; 167 std::map<std::string, std::string> attr_map; 168 for (size_t i = 0; i < arraysize(kEnterpriseAttributes); ++i) { 169 std::string value; 170 if (cryptohome_->InstallAttributesGet(kEnterpriseAttributes[i], &value)) 171 attr_map[kEnterpriseAttributes[i]] = value; 172 } 173 174 DecodeInstallAttributes(attr_map); 175 } 176 } 177 callback.Run(); 178} 179 180void EnterpriseInstallAttributes::LockDevice( 181 const std::string& user, 182 DeviceMode device_mode, 183 const std::string& device_id, 184 const LockResultCallback& callback) { 185 DCHECK(!callback.is_null()); 186 CHECK_NE(device_mode, DEVICE_MODE_PENDING); 187 CHECK_NE(device_mode, DEVICE_MODE_NOT_SET); 188 189 // Check for existing lock first. 190 if (device_locked_) { 191 if (device_mode == DEVICE_MODE_CONSUMER_KIOSK) { 192 callback.Run((registration_mode_ == device_mode) ? LOCK_SUCCESS : 193 LOCK_NOT_READY); 194 } else { 195 std::string domain = gaia::ExtractDomainName(user); 196 callback.Run( 197 (!registration_domain_.empty() && domain == registration_domain_) ? 198 LOCK_SUCCESS : LOCK_WRONG_USER); 199 } 200 return; 201 } 202 203 cryptohome_client_->InstallAttributesIsReady( 204 base::Bind(&EnterpriseInstallAttributes::LockDeviceIfAttributesIsReady, 205 weak_ptr_factory_.GetWeakPtr(), 206 user, 207 device_mode, 208 device_id, 209 callback)); 210} 211 212void EnterpriseInstallAttributes::LockDeviceIfAttributesIsReady( 213 const std::string& user, 214 DeviceMode device_mode, 215 const std::string& device_id, 216 const LockResultCallback& callback, 217 chromeos::DBusMethodCallStatus call_status, 218 bool result) { 219 if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS || !result) { 220 callback.Run(LOCK_NOT_READY); 221 return; 222 } 223 224 // Clearing the TPM password seems to be always a good deal. 225 if (cryptohome_->TpmIsEnabled() && 226 !cryptohome_->TpmIsBeingOwned() && 227 cryptohome_->TpmIsOwned()) { 228 cryptohome_->TpmClearStoredPassword(); 229 } 230 231 // Make sure we really have a working InstallAttrs. 232 if (cryptohome_->InstallAttributesIsInvalid()) { 233 LOG(ERROR) << "Install attributes invalid."; 234 callback.Run(LOCK_BACKEND_ERROR); 235 return; 236 } 237 238 if (!cryptohome_->InstallAttributesIsFirstInstall()) { 239 callback.Run(LOCK_WRONG_USER); 240 return; 241 } 242 243 std::string mode = GetDeviceModeString(device_mode); 244 std::string registration_user; 245 if (!user.empty()) 246 registration_user = gaia::CanonicalizeEmail(user); 247 248 if (device_mode == DEVICE_MODE_CONSUMER_KIOSK) { 249 // Set values in the InstallAttrs and lock it. 250 if (!cryptohome_->InstallAttributesSet(kAttrConsumerKioskEnabled, "true")) { 251 LOG(ERROR) << "Failed writing attributes"; 252 callback.Run(LOCK_BACKEND_ERROR); 253 return; 254 } 255 } else { 256 std::string domain = gaia::ExtractDomainName(registration_user); 257 // Set values in the InstallAttrs and lock it. 258 if (!cryptohome_->InstallAttributesSet(kAttrEnterpriseOwned, "true") || 259 !cryptohome_->InstallAttributesSet(kAttrEnterpriseUser, 260 registration_user) || 261 !cryptohome_->InstallAttributesSet(kAttrEnterpriseDomain, domain) || 262 !cryptohome_->InstallAttributesSet(kAttrEnterpriseMode, mode) || 263 !cryptohome_->InstallAttributesSet(kAttrEnterpriseDeviceId, 264 device_id)) { 265 LOG(ERROR) << "Failed writing attributes"; 266 callback.Run(LOCK_BACKEND_ERROR); 267 return; 268 } 269 } 270 271 if (!cryptohome_->InstallAttributesFinalize() || 272 cryptohome_->InstallAttributesIsFirstInstall()) { 273 LOG(ERROR) << "Failed locking."; 274 callback.Run(LOCK_BACKEND_ERROR); 275 return; 276 } 277 278 ReadImmutableAttributes( 279 base::Bind(&EnterpriseInstallAttributes::OnReadImmutableAttributes, 280 weak_ptr_factory_.GetWeakPtr(), 281 registration_user, 282 callback)); 283} 284 285void EnterpriseInstallAttributes::OnReadImmutableAttributes( 286 const std::string& registration_user, 287 const LockResultCallback& callback) { 288 289 if (GetRegistrationUser() != registration_user) { 290 LOG(ERROR) << "Locked data doesn't match"; 291 callback.Run(LOCK_BACKEND_ERROR); 292 return; 293 } 294 295 callback.Run(LOCK_SUCCESS); 296} 297 298bool EnterpriseInstallAttributes::IsEnterpriseDevice() { 299 return device_locked_ && !registration_user_.empty(); 300} 301 302bool EnterpriseInstallAttributes::IsConsumerKioskDevice() { 303 return device_locked_ && registration_mode_ == DEVICE_MODE_CONSUMER_KIOSK; 304} 305 306std::string EnterpriseInstallAttributes::GetRegistrationUser() { 307 if (!device_locked_) 308 return std::string(); 309 310 return registration_user_; 311} 312 313std::string EnterpriseInstallAttributes::GetDomain() { 314 if (!IsEnterpriseDevice()) 315 return std::string(); 316 317 return registration_domain_; 318} 319 320std::string EnterpriseInstallAttributes::GetDeviceId() { 321 if (!IsEnterpriseDevice()) 322 return std::string(); 323 324 return registration_device_id_; 325} 326 327DeviceMode EnterpriseInstallAttributes::GetMode() { 328 return registration_mode_; 329} 330 331void EnterpriseInstallAttributes::DecodeInstallAttributes( 332 const std::map<std::string, std::string>& attr_map) { 333 std::string enterprise_owned; 334 std::string enterprise_user; 335 std::string consumer_kiosk_enabled; 336 if (ReadMapKey(attr_map, kAttrEnterpriseOwned, &enterprise_owned) && 337 ReadMapKey(attr_map, kAttrEnterpriseUser, &enterprise_user) && 338 enterprise_owned == "true" && 339 !enterprise_user.empty()) { 340 registration_user_ = gaia::CanonicalizeEmail(enterprise_user); 341 342 // Initialize the mode to the legacy enterprise mode here and update 343 // below if more information is present. 344 registration_mode_ = DEVICE_MODE_ENTERPRISE; 345 346 // If we could extract basic setting we should try to extract the 347 // extended ones too. We try to set these to defaults as good as 348 // as possible if present, which could happen for device enrolled in 349 // pre 19 revisions of the code, before these new attributes were added. 350 if (ReadMapKey(attr_map, kAttrEnterpriseDomain, ®istration_domain_)) 351 registration_domain_ = gaia::CanonicalizeDomain(registration_domain_); 352 else 353 registration_domain_ = gaia::ExtractDomainName(registration_user_); 354 355 ReadMapKey(attr_map, kAttrEnterpriseDeviceId, ®istration_device_id_); 356 357 std::string mode; 358 if (ReadMapKey(attr_map, kAttrEnterpriseMode, &mode)) 359 registration_mode_ = GetDeviceModeFromString(mode); 360 } else if (ReadMapKey(attr_map, 361 kAttrConsumerKioskEnabled, 362 &consumer_kiosk_enabled) && 363 consumer_kiosk_enabled == "true") { 364 registration_mode_ = DEVICE_MODE_CONSUMER_KIOSK; 365 } else if (enterprise_user.empty() && enterprise_owned != "true") { 366 // |registration_user_| is empty on consumer devices. 367 registration_mode_ = DEVICE_MODE_CONSUMER; 368 } 369} 370 371} // namespace policy 372