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.
5 #include "chromeos/tpm/install_attributes.h"
11 #include "base/bind.h"
12 #include "base/files/file_util.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/metrics/histogram_base.h"
16 #include "base/metrics/histogram_macros.h"
17 #include "base/path_service.h"
18 #include "base/single_thread_task_runner.h"
19 #include "base/stl_util.h"
20 #include "base/system/sys_info.h"
21 #include "base/threading/thread_task_runner_handle.h"
22 #include "base/time/time.h"
23 #include "chromeos/dbus/constants/dbus_paths.h"
24 #include "chromeos/dbus/cryptohome/rpc.pb.h"
25 #include "chromeos/dbus/cryptohome/tpm_util.h"
26 #include "components/policy/proto/install_attributes.pb.h"
27 #include "google_apis/gaia/gaia_auth_util.h"
28 #include "third_party/cros_system_api/dbus/service_constants.h"
34 InstallAttributes* g_install_attributes = nullptr;
36 // Calling SetForTesting sets this flag. This flag means that the production
37 // code which calls Initialize and Shutdown will have no effect - the test
38 // install attributes will remain in place until ShutdownForTesting is called.
39 bool g_using_install_attributes_for_testing = false;
41 // Number of TPM lock state query retries during consistency check.
42 const int kDbusRetryCount = 12;
44 // Interval of TPM lock state query retries during consistency check.
45 const int kDbusRetryIntervalInSeconds = 5;
47 std::string ReadMapKey(const std::map<std::string, std::string>& map,
48 const std::string& key) {
49 std::map<std::string, std::string>::const_iterator entry = map.find(key);
50 if (entry != map.end()) {
56 void WarnIfNonempty(const std::map<std::string, std::string>& map,
57 const std::string& key) {
58 if (!ReadMapKey(map, key).empty()) {
59 LOG(WARNING) << key << " expected to be empty.";
63 // Reports the metric for whether the locking succeeded with existing locked
64 // attributes equal to the requested ones.
65 void ReportExistingLockUma(bool is_existing_lock) {
66 UMA_HISTOGRAM_BOOLEAN("Enterprise.ExistingInstallAttributesLock",
73 void InstallAttributes::Initialize() {
74 // Don't reinitialize if a specific instance has already been set for test.
75 if (g_using_install_attributes_for_testing)
78 DCHECK(!g_install_attributes);
79 g_install_attributes = new InstallAttributes(CryptohomeClient::Get());
80 base::FilePath install_attrs_file;
81 CHECK(base::PathService::Get(dbus_paths::FILE_INSTALL_ATTRIBUTES,
82 &install_attrs_file));
83 g_install_attributes->Init(install_attrs_file);
87 bool InstallAttributes::IsInitialized() {
88 return g_install_attributes;
92 void InstallAttributes::Shutdown() {
93 if (g_using_install_attributes_for_testing)
96 DCHECK(g_install_attributes);
97 delete g_install_attributes;
98 g_install_attributes = nullptr;
102 InstallAttributes* InstallAttributes::Get() {
103 DCHECK(g_install_attributes);
104 return g_install_attributes;
108 void InstallAttributes::SetForTesting(InstallAttributes* test_instance) {
109 DCHECK(!g_install_attributes);
110 DCHECK(!g_using_install_attributes_for_testing);
111 g_install_attributes = test_instance;
112 g_using_install_attributes_for_testing = true;
116 void InstallAttributes::ShutdownForTesting() {
117 DCHECK(g_using_install_attributes_for_testing);
118 // Don't delete the test instance, we are not the owner.
119 g_install_attributes = nullptr;
120 g_using_install_attributes_for_testing = false;
123 InstallAttributes::InstallAttributes(CryptohomeClient* cryptohome_client)
124 : cryptohome_client_(cryptohome_client) {}
126 InstallAttributes::~InstallAttributes() {}
128 void InstallAttributes::Init(const base::FilePath& cache_file) {
129 DCHECK(!device_locked_);
131 // Mark the consistency check as running to ensure that LockDevice() is
132 // blocked, but wait for the cryptohome service to be available before
133 // actually calling TriggerConsistencyCheck().
134 consistency_check_running_ = true;
135 cryptohome_client_->WaitForServiceToBeAvailable(
136 base::BindOnce(&InstallAttributes::OnCryptohomeServiceInitiallyAvailable,
137 weak_ptr_factory_.GetWeakPtr()));
139 if (!base::PathExists(cache_file)) {
140 LOG_IF(WARNING, base::SysInfo::IsRunningOnChromeOS())
141 << "Install attributes missing, first sign in";
145 device_locked_ = true;
148 int len = base::ReadFile(cache_file, buf, sizeof(buf));
149 if (len == -1 || len >= static_cast<int>(sizeof(buf))) {
150 PLOG(ERROR) << "Failed to read " << cache_file.value();
154 cryptohome::SerializedInstallAttributes install_attrs_proto;
155 if (!install_attrs_proto.ParseFromArray(buf, len)) {
156 LOG(ERROR) << "Failed to parse install attributes cache.";
160 google::protobuf::RepeatedPtrField<
161 const cryptohome::SerializedInstallAttributes::Attribute>::iterator entry;
162 std::map<std::string, std::string> attr_map;
163 for (entry = install_attrs_proto.attributes().begin();
164 entry != install_attrs_proto.attributes().end(); ++entry) {
165 // The protobuf values contain terminating null characters, so we have to
166 // sanitize the value here.
168 std::make_pair(entry->name(), std::string(entry->value().c_str())));
171 DecodeInstallAttributes(attr_map);
174 void InstallAttributes::ReadImmutableAttributes(base::OnceClosure callback) {
175 if (device_locked_) {
176 std::move(callback).Run();
180 cryptohome_client_->InstallAttributesIsReady(
181 base::BindOnce(&InstallAttributes::ReadAttributesIfReady,
182 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
185 void InstallAttributes::ReadAttributesIfReady(base::OnceClosure callback,
186 base::Optional<bool> is_ready) {
187 if (is_ready.value_or(false)) {
188 registration_mode_ = policy::DEVICE_MODE_NOT_SET;
189 if (!tpm_util::InstallAttributesIsInvalid() &&
190 !tpm_util::InstallAttributesIsFirstInstall()) {
191 device_locked_ = true;
193 static const char* const kEnterpriseAttributes[] = {
194 kAttrEnterpriseDeviceId, kAttrEnterpriseDomain,
195 kAttrEnterpriseRealm, kAttrEnterpriseMode,
196 kAttrEnterpriseOwned, kAttrEnterpriseUser,
197 kAttrConsumerKioskEnabled,
199 std::map<std::string, std::string> attr_map;
200 for (size_t i = 0; i < base::size(kEnterpriseAttributes); ++i) {
202 if (tpm_util::InstallAttributesGet(kEnterpriseAttributes[i], &value))
203 attr_map[kEnterpriseAttributes[i]] = value;
206 DecodeInstallAttributes(attr_map);
209 std::move(callback).Run();
212 void InstallAttributes::SetBlockDevmodeInTpm(
214 DBusMethodCallback<cryptohome::BaseReply> callback) {
215 DCHECK(!callback.is_null());
216 DCHECK(!device_locked_);
218 cryptohome::SetFirmwareManagementParametersRequest request;
219 // Set the flags, according to enum FirmwareManagementParametersFlags from
220 // rpc.proto if devmode is blocked.
223 cryptohome::DEVELOPER_DISABLE_BOOT |
224 cryptohome::DEVELOPER_DISABLE_CASE_CLOSED_DEBUGGING_UNLOCK);
227 cryptohome_client_->SetFirmwareManagementParametersInTpm(request,
228 std::move(callback));
231 void InstallAttributes::LockDevice(policy::DeviceMode device_mode,
232 const std::string& domain,
233 const std::string& realm,
234 const std::string& device_id,
235 LockResultCallback callback) {
236 CHECK((device_mode == policy::DEVICE_MODE_ENTERPRISE && !domain.empty() &&
237 realm.empty() && !device_id.empty()) ||
238 (device_mode == policy::DEVICE_MODE_ENTERPRISE_AD && domain.empty() &&
239 !realm.empty() && !device_id.empty()) ||
240 (device_mode == policy::DEVICE_MODE_DEMO && !domain.empty() &&
241 realm.empty() && !device_id.empty()) ||
242 (device_mode == policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH &&
243 domain.empty() && realm.empty() && device_id.empty()));
245 CHECK_EQ(device_lock_running_, false);
247 // Check for existing lock first.
248 if (device_locked_) {
249 if (device_mode != registration_mode_) {
250 LOG(ERROR) << "Trying to re-lock with wrong mode: device_mode: "
252 << ", registration_mode: " << registration_mode_;
253 std::move(callback).Run(LOCK_WRONG_MODE);
257 if (domain != registration_domain_ || realm != registration_realm_ ||
258 device_id != registration_device_id_) {
259 LOG(ERROR) << "Trying to re-lock with non-matching parameters.";
260 std::move(callback).Run(LOCK_WRONG_DOMAIN);
264 // Already locked in the right mode, signal success.
265 ReportExistingLockUma(true /* is_existing_lock */);
266 std::move(callback).Run(LOCK_SUCCESS);
270 // In case the consistency check is still running, postpone the device locking
271 // until it has finished. This should not introduce additional delay since
272 // device locking must wait for TPM initialization anyways.
273 if (consistency_check_running_) {
274 CHECK(post_check_action_.is_null());
275 post_check_action_ = base::BindOnce(
276 &InstallAttributes::LockDevice, weak_ptr_factory_.GetWeakPtr(),
277 device_mode, domain, realm, device_id, std::move(callback));
281 device_lock_running_ = true;
282 cryptohome_client_->InstallAttributesIsReady(
283 base::BindOnce(&InstallAttributes::LockDeviceIfAttributesIsReady,
284 weak_ptr_factory_.GetWeakPtr(), device_mode, domain, realm,
285 device_id, std::move(callback)));
288 void InstallAttributes::LockDeviceIfAttributesIsReady(
289 policy::DeviceMode device_mode,
290 const std::string& domain,
291 const std::string& realm,
292 const std::string& device_id,
293 LockResultCallback callback,
294 base::Optional<bool> is_ready) {
295 if (!is_ready.has_value() || !is_ready.value()) {
296 device_lock_running_ = false;
297 std::move(callback).Run(LOCK_NOT_READY);
301 // Clearing the TPM password seems to be always a good deal.
302 if (tpm_util::TpmIsEnabled() && !tpm_util::TpmIsBeingOwned() &&
303 tpm_util::TpmIsOwned()) {
304 cryptohome_client_->CallTpmClearStoredPasswordAndBlock();
307 // Make sure we really have a working InstallAttrs.
308 if (tpm_util::InstallAttributesIsInvalid()) {
309 LOG(ERROR) << "Install attributes invalid.";
310 device_lock_running_ = false;
311 std::move(callback).Run(LOCK_BACKEND_INVALID);
315 if (!tpm_util::InstallAttributesIsFirstInstall()) {
316 LOG(ERROR) << "Install attributes already installed.";
317 device_lock_running_ = false;
318 std::move(callback).Run(LOCK_ALREADY_LOCKED);
322 // Set values in the InstallAttrs.
323 std::string kiosk_enabled, enterprise_owned;
324 if (device_mode == policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH) {
325 kiosk_enabled = "true";
327 enterprise_owned = "true";
329 std::string mode = GetDeviceModeString(device_mode);
330 if (!tpm_util::InstallAttributesSet(kAttrConsumerKioskEnabled,
332 !tpm_util::InstallAttributesSet(kAttrEnterpriseOwned, enterprise_owned) ||
333 !tpm_util::InstallAttributesSet(kAttrEnterpriseMode, mode) ||
334 !tpm_util::InstallAttributesSet(kAttrEnterpriseDomain, domain) ||
335 !tpm_util::InstallAttributesSet(kAttrEnterpriseRealm, realm) ||
336 !tpm_util::InstallAttributesSet(kAttrEnterpriseDeviceId, device_id)) {
337 LOG(ERROR) << "Failed writing attributes.";
338 device_lock_running_ = false;
339 std::move(callback).Run(LOCK_SET_ERROR);
343 if (!tpm_util::InstallAttributesFinalize() ||
344 tpm_util::InstallAttributesIsFirstInstall()) {
345 LOG(ERROR) << "Failed locking.";
346 device_lock_running_ = false;
347 std::move(callback).Run(LOCK_FINALIZE_ERROR);
351 ReadImmutableAttributes(
352 base::BindOnce(&InstallAttributes::OnReadImmutableAttributes,
353 weak_ptr_factory_.GetWeakPtr(), device_mode, domain, realm,
354 device_id, std::move(callback)));
357 void InstallAttributes::OnReadImmutableAttributes(policy::DeviceMode mode,
358 const std::string& domain,
359 const std::string& realm,
360 const std::string& device_id,
361 LockResultCallback callback) {
362 device_lock_running_ = false;
364 if (registration_mode_ != mode || registration_domain_ != domain ||
365 registration_realm_ != realm || registration_device_id_ != device_id) {
366 LOG(ERROR) << "Locked data doesn't match.";
367 std::move(callback).Run(LOCK_READBACK_ERROR);
371 ReportExistingLockUma(false /* is_existing_lock */);
372 std::move(callback).Run(LOCK_SUCCESS);
375 bool InstallAttributes::IsEnterpriseManaged() const {
376 if (!device_locked_) {
379 return registration_mode_ == policy::DEVICE_MODE_ENTERPRISE ||
380 registration_mode_ == policy::DEVICE_MODE_ENTERPRISE_AD ||
381 registration_mode_ == policy::DEVICE_MODE_DEMO;
384 bool InstallAttributes::IsActiveDirectoryManaged() const {
385 if (!device_locked_) {
388 return registration_mode_ == policy::DEVICE_MODE_ENTERPRISE_AD;
391 bool InstallAttributes::IsCloudManaged() const {
392 if (!device_locked_) {
395 return registration_mode_ == policy::DEVICE_MODE_ENTERPRISE ||
396 registration_mode_ == policy::DEVICE_MODE_DEMO;
399 bool InstallAttributes::IsConsumerKioskDeviceWithAutoLaunch() {
400 return device_locked_ &&
401 registration_mode_ == policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH;
404 void InstallAttributes::TriggerConsistencyCheck(int dbus_retries) {
405 cryptohome_client_->TpmGetPassword(
406 base::BindOnce(&InstallAttributes::OnTpmGetPasswordCompleted,
407 weak_ptr_factory_.GetWeakPtr(), dbus_retries));
410 void InstallAttributes::OnTpmGetPasswordCompleted(
411 int dbus_retries_remaining,
412 base::Optional<std::string> result) {
413 if (!result.has_value() && dbus_retries_remaining) {
414 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
416 base::BindOnce(&InstallAttributes::TriggerConsistencyCheck,
417 weak_ptr_factory_.GetWeakPtr(),
418 dbus_retries_remaining - 1),
419 base::TimeDelta::FromSeconds(kDbusRetryIntervalInSeconds));
423 base::HistogramBase::Sample state;
424 // If the result has a value, we are interested if install attributes file
425 // exists (device_locked_), if the device is enrolled (registration_mode_) and
426 // if the TPM is locked, meaning the TPM password is deleted so
427 // the value from result is empty.
428 if (result.has_value()) {
429 const bool is_cloud_managed =
430 registration_mode_ == policy::DEVICE_MODE_ENTERPRISE ||
431 registration_mode_ == policy::DEVICE_MODE_DEMO;
432 state = (device_locked_ ? 1 : 0) | (is_cloud_managed ? 2 : 0) |
433 (result->empty() ? 4 : 0);
437 UMA_HISTOGRAM_ENUMERATION("Enterprise.AttributesTPMConsistency", state, 9);
439 // Run any action (LockDevice call) that might have queued behind the
440 // consistency check.
441 consistency_check_running_ = false;
442 if (post_check_action_) {
443 std::move(post_check_action_).Run();
444 post_check_action_.Reset();
448 // Warning: The values for these keys (but not the keys themselves) are stored
449 // in the protobuf with a trailing zero. Also note that some of these constants
450 // have been copied to login_manager/device_policy_service.cc. Please make sure
451 // that all changes to the constants are reflected there as well.
452 const char InstallAttributes::kConsumerDeviceMode[] = "consumer";
453 const char InstallAttributes::kEnterpriseDeviceMode[] = "enterprise";
454 const char InstallAttributes::kEnterpriseADDeviceMode[] = "enterprise_ad";
455 const char InstallAttributes::kLegacyRetailDeviceMode[] = "kiosk";
456 const char InstallAttributes::kConsumerKioskDeviceMode[] = "consumer_kiosk";
457 const char InstallAttributes::kDemoDeviceMode[] = "demo_mode";
459 const char InstallAttributes::kAttrEnterpriseDeviceId[] =
460 "enterprise.device_id";
461 const char InstallAttributes::kAttrEnterpriseDomain[] = "enterprise.domain";
462 const char InstallAttributes::kAttrEnterpriseRealm[] = "enterprise.realm";
463 const char InstallAttributes::kAttrEnterpriseMode[] = "enterprise.mode";
464 const char InstallAttributes::kAttrEnterpriseOwned[] = "enterprise.owned";
465 const char InstallAttributes::kAttrEnterpriseUser[] = "enterprise.user";
466 const char InstallAttributes::kAttrConsumerKioskEnabled[] =
467 "consumer.app_kiosk_enabled";
469 void InstallAttributes::OnCryptohomeServiceInitiallyAvailable(
470 bool service_is_ready) {
471 if (!service_is_ready)
472 LOG(ERROR) << "Failed waiting for cryptohome D-Bus service availability.";
474 // Start the consistency check even if we failed to wait for availability;
475 // hopefully the service will become available eventually.
476 TriggerConsistencyCheck(kDbusRetryCount);
479 std::string InstallAttributes::GetDeviceModeString(policy::DeviceMode mode) {
481 case policy::DEVICE_MODE_CONSUMER:
482 return InstallAttributes::kConsumerDeviceMode;
483 case policy::DEVICE_MODE_ENTERPRISE:
484 return InstallAttributes::kEnterpriseDeviceMode;
485 case policy::DEVICE_MODE_ENTERPRISE_AD:
486 return InstallAttributes::kEnterpriseADDeviceMode;
487 case policy::DEVICE_MODE_LEGACY_RETAIL_MODE:
488 return InstallAttributes::kLegacyRetailDeviceMode;
489 case policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH:
490 return InstallAttributes::kConsumerKioskDeviceMode;
491 case policy::DEVICE_MODE_DEMO:
492 return InstallAttributes::kDemoDeviceMode;
493 case policy::DEVICE_MODE_PENDING:
494 case policy::DEVICE_MODE_NOT_SET:
497 NOTREACHED() << "Invalid device mode: " << mode;
498 return std::string();
501 policy::DeviceMode InstallAttributes::GetDeviceModeFromString(
502 const std::string& mode) {
503 if (mode == InstallAttributes::kConsumerDeviceMode)
504 return policy::DEVICE_MODE_CONSUMER;
505 if (mode == InstallAttributes::kEnterpriseDeviceMode)
506 return policy::DEVICE_MODE_ENTERPRISE;
507 if (mode == InstallAttributes::kEnterpriseADDeviceMode)
508 return policy::DEVICE_MODE_ENTERPRISE_AD;
509 if (mode == InstallAttributes::kLegacyRetailDeviceMode)
510 return policy::DEVICE_MODE_LEGACY_RETAIL_MODE;
511 if (mode == InstallAttributes::kConsumerKioskDeviceMode)
512 return policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH;
513 if (mode == InstallAttributes::kDemoDeviceMode)
514 return policy::DEVICE_MODE_DEMO;
515 return policy::DEVICE_MODE_NOT_SET;
518 void InstallAttributes::DecodeInstallAttributes(
519 const std::map<std::string, std::string>& attr_map) {
520 // Start from a clean slate.
521 registration_mode_ = policy::DEVICE_MODE_NOT_SET;
522 registration_domain_.clear();
523 registration_realm_.clear();
524 registration_device_id_.clear();
526 const std::string enterprise_owned =
527 ReadMapKey(attr_map, kAttrEnterpriseOwned);
528 const std::string consumer_kiosk_enabled =
529 ReadMapKey(attr_map, kAttrConsumerKioskEnabled);
530 const std::string mode = ReadMapKey(attr_map, kAttrEnterpriseMode);
531 const std::string domain = ReadMapKey(attr_map, kAttrEnterpriseDomain);
532 const std::string realm = ReadMapKey(attr_map, kAttrEnterpriseRealm);
533 const std::string device_id = ReadMapKey(attr_map, kAttrEnterpriseDeviceId);
534 const std::string user_deprecated = ReadMapKey(attr_map, kAttrEnterpriseUser);
536 if (enterprise_owned == "true") {
537 WarnIfNonempty(attr_map, kAttrConsumerKioskEnabled);
538 registration_device_id_ = device_id;
540 // Set registration_mode_.
541 registration_mode_ = GetDeviceModeFromString(mode);
542 if (registration_mode_ != policy::DEVICE_MODE_ENTERPRISE &&
543 registration_mode_ != policy::DEVICE_MODE_ENTERPRISE_AD &&
544 registration_mode_ != policy::DEVICE_MODE_DEMO) {
546 LOG(WARNING) << "Bad " << kAttrEnterpriseMode << ": " << mode;
548 registration_mode_ = policy::DEVICE_MODE_ENTERPRISE;
551 if (registration_mode_ == policy::DEVICE_MODE_ENTERPRISE ||
552 registration_mode_ == policy::DEVICE_MODE_DEMO) {
553 // Either set registration_domain_ ...
554 WarnIfNonempty(attr_map, kAttrEnterpriseRealm);
555 if (!domain.empty()) {
556 // The canonicalization is for compatibility with earlier versions.
557 registration_domain_ = gaia::CanonicalizeDomain(domain);
558 } else if (!user_deprecated.empty()) {
559 // Compatibility for pre M19 code.
560 registration_domain_ = gaia::ExtractDomainName(user_deprecated);
562 LOG(WARNING) << "Couldn't read domain.";
565 // ... or set registration_realm_.
566 WarnIfNonempty(attr_map, kAttrEnterpriseDomain);
567 if (!realm.empty()) {
568 registration_realm_ = realm;
570 LOG(WARNING) << "Couldn't read realm.";
577 WarnIfNonempty(attr_map, kAttrEnterpriseOwned);
578 WarnIfNonempty(attr_map, kAttrEnterpriseDomain);
579 WarnIfNonempty(attr_map, kAttrEnterpriseRealm);
580 WarnIfNonempty(attr_map, kAttrEnterpriseDeviceId);
581 WarnIfNonempty(attr_map, kAttrEnterpriseUser);
582 if (consumer_kiosk_enabled == "true") {
583 registration_mode_ = policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH;
587 WarnIfNonempty(attr_map, kAttrConsumerKioskEnabled);
588 if (user_deprecated.empty()) {
589 registration_mode_ = policy::DEVICE_MODE_CONSUMER;
593 } // namespace chromeos