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 "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
10 #include "base/files/file_util.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/metrics/histogram_base.h"
15 #include "base/metrics/histogram_macros.h"
16 #include "base/time/time.h"
17 #include "chrome/browser/chromeos/policy/proto/install_attributes.pb.h"
18 #include "chromeos/cryptohome/cryptohome_util.h"
19 #include "chromeos/dbus/dbus_thread_manager.h"
20 #include "google_apis/gaia/gaia_auth_util.h"
24 namespace cryptohome_util
= chromeos::cryptohome_util
;
28 // Number of TPM lock state query retries during consistency check.
29 int kDbusRetryCount
= 12;
31 // Interval of TPM lock state query retries during consistency check.
32 int kDbusRetryIntervalInSeconds
= 5;
34 bool ReadMapKey(const std::map
<std::string
, std::string
>& map
,
35 const std::string
& key
,
37 std::map
<std::string
, std::string
>::const_iterator entry
= map
.find(key
);
38 if (entry
== map
.end())
41 *value
= entry
->second
;
49 EnterpriseInstallAttributes::GetEnterpriseOwnedInstallAttributesBlobForTesting(
50 const std::string
& user_name
) {
51 cryptohome::SerializedInstallAttributes install_attrs_proto
;
52 cryptohome::SerializedInstallAttributes::Attribute
* attribute
= NULL
;
54 attribute
= install_attrs_proto
.add_attributes();
55 attribute
->set_name(EnterpriseInstallAttributes::kAttrEnterpriseOwned
);
56 attribute
->set_value("true");
58 attribute
= install_attrs_proto
.add_attributes();
59 attribute
->set_name(EnterpriseInstallAttributes::kAttrEnterpriseUser
);
60 attribute
->set_value(user_name
);
62 return install_attrs_proto
.SerializeAsString();
65 EnterpriseInstallAttributes::EnterpriseInstallAttributes(
66 chromeos::CryptohomeClient
* cryptohome_client
)
67 : device_locked_(false),
68 consistency_check_running_(false),
69 device_lock_running_(false),
70 registration_mode_(DEVICE_MODE_PENDING
),
71 cryptohome_client_(cryptohome_client
),
72 weak_ptr_factory_(this) {
75 EnterpriseInstallAttributes::~EnterpriseInstallAttributes() {}
77 void EnterpriseInstallAttributes::Init(const base::FilePath
& cache_file
) {
78 DCHECK_EQ(false, device_locked_
);
80 // The actual check happens asynchronously, thus it is ok to trigger it before
81 // Init() has completed.
82 TriggerConsistencyCheck(kDbusRetryCount
* kDbusRetryIntervalInSeconds
);
84 if (!base::PathExists(cache_file
))
87 device_locked_
= true;
90 int len
= base::ReadFile(cache_file
, buf
, sizeof(buf
));
91 if (len
== -1 || len
>= static_cast<int>(sizeof(buf
))) {
92 PLOG(ERROR
) << "Failed to read " << cache_file
.value();
96 cryptohome::SerializedInstallAttributes install_attrs_proto
;
97 if (!install_attrs_proto
.ParseFromArray(buf
, len
)) {
98 LOG(ERROR
) << "Failed to parse install attributes cache";
102 google::protobuf::RepeatedPtrField
<
103 const cryptohome::SerializedInstallAttributes::Attribute
>::iterator entry
;
104 std::map
<std::string
, std::string
> attr_map
;
105 for (entry
= install_attrs_proto
.attributes().begin();
106 entry
!= install_attrs_proto
.attributes().end();
108 // The protobuf values unfortunately contain terminating null characters, so
109 // we have to sanitize the value here.
110 attr_map
.insert(std::make_pair(entry
->name(),
111 std::string(entry
->value().c_str())));
114 DecodeInstallAttributes(attr_map
);
117 void EnterpriseInstallAttributes::ReadImmutableAttributes(
118 const base::Closure
& callback
) {
119 if (device_locked_
) {
124 cryptohome_client_
->InstallAttributesIsReady(
125 base::Bind(&EnterpriseInstallAttributes::ReadAttributesIfReady
,
126 weak_ptr_factory_
.GetWeakPtr(),
130 void EnterpriseInstallAttributes::ReadAttributesIfReady(
131 const base::Closure
& callback
,
132 chromeos::DBusMethodCallStatus call_status
,
134 if (call_status
== chromeos::DBUS_METHOD_CALL_SUCCESS
&& result
) {
135 registration_mode_
= DEVICE_MODE_NOT_SET
;
136 if (!cryptohome_util::InstallAttributesIsInvalid() &&
137 !cryptohome_util::InstallAttributesIsFirstInstall()) {
138 device_locked_
= true;
140 static const char* const kEnterpriseAttributes
[] = {
141 kAttrEnterpriseDeviceId
,
142 kAttrEnterpriseDomain
,
144 kAttrEnterpriseOwned
,
146 kAttrConsumerKioskEnabled
,
148 std::map
<std::string
, std::string
> attr_map
;
149 for (size_t i
= 0; i
< arraysize(kEnterpriseAttributes
); ++i
) {
151 if (cryptohome_util::InstallAttributesGet(kEnterpriseAttributes
[i
],
153 attr_map
[kEnterpriseAttributes
[i
]] = value
;
156 DecodeInstallAttributes(attr_map
);
162 void EnterpriseInstallAttributes::LockDevice(
163 const std::string
& user
,
164 DeviceMode device_mode
,
165 const std::string
& device_id
,
166 const LockResultCallback
& callback
) {
167 DCHECK(!callback
.is_null());
168 CHECK_EQ(device_lock_running_
, false);
169 CHECK_NE(device_mode
, DEVICE_MODE_PENDING
);
170 CHECK_NE(device_mode
, DEVICE_MODE_NOT_SET
);
172 // Check for existing lock first.
173 if (device_locked_
) {
174 if (device_mode
!= registration_mode_
) {
175 callback
.Run(LOCK_WRONG_MODE
);
179 switch (registration_mode_
) {
180 case DEVICE_MODE_ENTERPRISE
:
181 case DEVICE_MODE_LEGACY_RETAIL_MODE
: {
182 // Check domain match for enterprise devices.
183 std::string domain
= gaia::ExtractDomainName(user
);
184 if (registration_domain_
.empty() || domain
!= registration_domain_
) {
185 callback
.Run(LOCK_WRONG_DOMAIN
);
190 case DEVICE_MODE_NOT_SET
:
191 case DEVICE_MODE_PENDING
:
192 // This case can't happen due to the CHECK_NE asserts above.
195 case DEVICE_MODE_CONSUMER
:
196 case DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH
:
197 // The user parameter is ignored for consumer devices.
201 // Already locked in the right mode, signal success.
202 callback
.Run(LOCK_SUCCESS
);
206 // In case the consistency check is still running, postpone the device locking
207 // until it has finished. This should not introduce additional delay since
208 // device locking must wait for TPM initialization anyways.
209 if (consistency_check_running_
) {
210 CHECK(post_check_action_
.is_null());
211 post_check_action_
= base::Bind(&EnterpriseInstallAttributes::LockDevice
,
212 weak_ptr_factory_
.GetWeakPtr(),
220 device_lock_running_
= true;
221 cryptohome_client_
->InstallAttributesIsReady(
222 base::Bind(&EnterpriseInstallAttributes::LockDeviceIfAttributesIsReady
,
223 weak_ptr_factory_
.GetWeakPtr(),
230 void EnterpriseInstallAttributes::LockDeviceIfAttributesIsReady(
231 const std::string
& user
,
232 DeviceMode device_mode
,
233 const std::string
& device_id
,
234 const LockResultCallback
& callback
,
235 chromeos::DBusMethodCallStatus call_status
,
237 if (call_status
!= chromeos::DBUS_METHOD_CALL_SUCCESS
|| !result
) {
238 device_lock_running_
= false;
239 callback
.Run(LOCK_NOT_READY
);
243 // Clearing the TPM password seems to be always a good deal.
244 if (cryptohome_util::TpmIsEnabled() &&
245 !cryptohome_util::TpmIsBeingOwned() &&
246 cryptohome_util::TpmIsOwned()) {
247 cryptohome_client_
->CallTpmClearStoredPasswordAndBlock();
250 // Make sure we really have a working InstallAttrs.
251 if (cryptohome_util::InstallAttributesIsInvalid()) {
252 LOG(ERROR
) << "Install attributes invalid.";
253 device_lock_running_
= false;
254 callback
.Run(LOCK_BACKEND_INVALID
);
258 if (!cryptohome_util::InstallAttributesIsFirstInstall()) {
259 LOG(ERROR
) << "Install attributes already installed.";
260 device_lock_running_
= false;
261 callback
.Run(LOCK_ALREADY_LOCKED
);
265 std::string mode
= GetDeviceModeString(device_mode
);
266 std::string registration_user
;
268 registration_user
= gaia::CanonicalizeEmail(user
);
270 if (device_mode
== DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH
) {
271 // Set values in the InstallAttrs and lock it.
272 if (!cryptohome_util::InstallAttributesSet(kAttrConsumerKioskEnabled
,
274 LOG(ERROR
) << "Failed writing attributes.";
275 device_lock_running_
= false;
276 callback
.Run(LOCK_SET_ERROR
);
280 std::string domain
= gaia::ExtractDomainName(registration_user
);
281 // Set values in the InstallAttrs and lock it.
282 if (!cryptohome_util::InstallAttributesSet(kAttrEnterpriseOwned
, "true") ||
283 !cryptohome_util::InstallAttributesSet(kAttrEnterpriseUser
,
284 registration_user
) ||
285 !cryptohome_util::InstallAttributesSet(kAttrEnterpriseDomain
,
287 !cryptohome_util::InstallAttributesSet(kAttrEnterpriseMode
, mode
) ||
288 !cryptohome_util::InstallAttributesSet(kAttrEnterpriseDeviceId
,
290 LOG(ERROR
) << "Failed writing attributes.";
291 device_lock_running_
= false;
292 callback
.Run(LOCK_SET_ERROR
);
297 if (!cryptohome_util::InstallAttributesFinalize() ||
298 cryptohome_util::InstallAttributesIsFirstInstall()) {
299 LOG(ERROR
) << "Failed locking.";
300 device_lock_running_
= false;
301 callback
.Run(LOCK_FINALIZE_ERROR
);
305 ReadImmutableAttributes(
306 base::Bind(&EnterpriseInstallAttributes::OnReadImmutableAttributes
,
307 weak_ptr_factory_
.GetWeakPtr(),
312 void EnterpriseInstallAttributes::OnReadImmutableAttributes(
313 const std::string
& registration_user
,
314 const LockResultCallback
& callback
) {
316 if (GetRegistrationUser() != registration_user
) {
317 LOG(ERROR
) << "Locked data doesn't match.";
318 device_lock_running_
= false;
319 callback
.Run(LOCK_READBACK_ERROR
);
323 device_lock_running_
= false;
324 callback
.Run(LOCK_SUCCESS
);
327 bool EnterpriseInstallAttributes::IsEnterpriseDevice() const {
328 return device_locked_
&& !registration_user_
.empty();
331 bool EnterpriseInstallAttributes::IsConsumerKioskDeviceWithAutoLaunch() {
332 return device_locked_
&&
333 registration_mode_
== DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH
;
336 std::string
EnterpriseInstallAttributes::GetRegistrationUser() {
338 return std::string();
340 return registration_user_
;
343 std::string
EnterpriseInstallAttributes::GetDomain() const {
344 if (!IsEnterpriseDevice())
345 return std::string();
347 return registration_domain_
;
350 std::string
EnterpriseInstallAttributes::GetDeviceId() {
351 if (!IsEnterpriseDevice())
352 return std::string();
354 return registration_device_id_
;
357 DeviceMode
EnterpriseInstallAttributes::GetMode() {
358 return registration_mode_
;
361 void EnterpriseInstallAttributes::TriggerConsistencyCheck(int dbus_retries
) {
362 consistency_check_running_
= true;
363 cryptohome_client_
->TpmIsOwned(
364 base::Bind(&EnterpriseInstallAttributes::OnTpmOwnerCheckCompleted
,
365 weak_ptr_factory_
.GetWeakPtr(),
369 void EnterpriseInstallAttributes::OnTpmOwnerCheckCompleted(
370 int dbus_retries_remaining
,
371 chromeos::DBusMethodCallStatus call_status
,
373 if (call_status
!= chromeos::DBUS_METHOD_CALL_SUCCESS
&&
374 dbus_retries_remaining
) {
375 base::MessageLoop::current()->PostDelayedTask(
377 base::Bind(&EnterpriseInstallAttributes::TriggerConsistencyCheck
,
378 weak_ptr_factory_
.GetWeakPtr(),
379 dbus_retries_remaining
- 1),
380 base::TimeDelta::FromSeconds(kDbusRetryIntervalInSeconds
));
384 base::HistogramBase::Sample state
= device_locked_
;
385 state
|= 0x2 * (registration_mode_
== DEVICE_MODE_ENTERPRISE
);
386 if (call_status
== chromeos::DBUS_METHOD_CALL_SUCCESS
)
387 state
|= 0x4 * result
;
389 state
= 0x8; // This case is not a bit mask.
390 UMA_HISTOGRAM_ENUMERATION("Enterprise.AttributesTPMConsistency", state
, 9);
392 // Run any action (LockDevice call) that might have queued behind the
393 // consistency check.
394 consistency_check_running_
= false;
395 if (!post_check_action_
.is_null()) {
396 post_check_action_
.Run();
397 post_check_action_
.Reset();
401 // Warning: The values for these keys (but not the keys themselves) are stored
402 // in the protobuf with a trailing zero. Also note that some of these constants
403 // have been copied to login_manager/device_policy_service.cc. Please make sure
404 // that all changes to the constants are reflected there as well.
405 const char EnterpriseInstallAttributes::kConsumerDeviceMode
[] = "consumer";
406 const char EnterpriseInstallAttributes::kEnterpriseDeviceMode
[] = "enterprise";
407 const char EnterpriseInstallAttributes::kLegacyRetailDeviceMode
[] = "kiosk";
408 const char EnterpriseInstallAttributes::kConsumerKioskDeviceMode
[] =
410 const char EnterpriseInstallAttributes::kUnknownDeviceMode
[] = "unknown";
412 const char EnterpriseInstallAttributes::kAttrEnterpriseDeviceId
[] =
413 "enterprise.device_id";
414 const char EnterpriseInstallAttributes::kAttrEnterpriseDomain
[] =
416 const char EnterpriseInstallAttributes::kAttrEnterpriseMode
[] =
418 const char EnterpriseInstallAttributes::kAttrEnterpriseOwned
[] =
420 const char EnterpriseInstallAttributes::kAttrEnterpriseUser
[] =
422 const char EnterpriseInstallAttributes::kAttrConsumerKioskEnabled
[] =
423 "consumer.app_kiosk_enabled";
425 std::string
EnterpriseInstallAttributes::GetDeviceModeString(DeviceMode mode
) {
427 case DEVICE_MODE_CONSUMER
:
428 return EnterpriseInstallAttributes::kConsumerDeviceMode
;
429 case DEVICE_MODE_ENTERPRISE
:
430 return EnterpriseInstallAttributes::kEnterpriseDeviceMode
;
431 case DEVICE_MODE_LEGACY_RETAIL_MODE
:
432 return EnterpriseInstallAttributes::kLegacyRetailDeviceMode
;
433 case DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH
:
434 return EnterpriseInstallAttributes::kConsumerKioskDeviceMode
;
435 case DEVICE_MODE_PENDING
:
436 case DEVICE_MODE_NOT_SET
:
439 NOTREACHED() << "Invalid device mode: " << mode
;
440 return EnterpriseInstallAttributes::kUnknownDeviceMode
;
443 DeviceMode
EnterpriseInstallAttributes::GetDeviceModeFromString(
444 const std::string
& mode
) {
445 if (mode
== EnterpriseInstallAttributes::kConsumerDeviceMode
)
446 return DEVICE_MODE_CONSUMER
;
447 else if (mode
== EnterpriseInstallAttributes::kEnterpriseDeviceMode
)
448 return DEVICE_MODE_ENTERPRISE
;
449 else if (mode
== EnterpriseInstallAttributes::kLegacyRetailDeviceMode
)
450 return DEVICE_MODE_LEGACY_RETAIL_MODE
;
451 else if (mode
== EnterpriseInstallAttributes::kConsumerKioskDeviceMode
)
452 return DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH
;
453 NOTREACHED() << "Unknown device mode string: " << mode
;
454 return DEVICE_MODE_NOT_SET
;
457 void EnterpriseInstallAttributes::DecodeInstallAttributes(
458 const std::map
<std::string
, std::string
>& attr_map
) {
459 std::string enterprise_owned
;
460 std::string enterprise_user
;
461 std::string consumer_kiosk_enabled
;
462 if (ReadMapKey(attr_map
, kAttrEnterpriseOwned
, &enterprise_owned
) &&
463 ReadMapKey(attr_map
, kAttrEnterpriseUser
, &enterprise_user
) &&
464 enterprise_owned
== "true" &&
465 !enterprise_user
.empty()) {
466 registration_user_
= gaia::CanonicalizeEmail(enterprise_user
);
468 // Initialize the mode to the legacy enterprise mode here and update
469 // below if more information is present.
470 registration_mode_
= DEVICE_MODE_ENTERPRISE
;
472 // If we could extract basic setting we should try to extract the
473 // extended ones too. We try to set these to defaults as good as
474 // as possible if present, which could happen for device enrolled in
475 // pre 19 revisions of the code, before these new attributes were added.
476 if (ReadMapKey(attr_map
, kAttrEnterpriseDomain
, ®istration_domain_
))
477 registration_domain_
= gaia::CanonicalizeDomain(registration_domain_
);
479 registration_domain_
= gaia::ExtractDomainName(registration_user_
);
481 ReadMapKey(attr_map
, kAttrEnterpriseDeviceId
, ®istration_device_id_
);
484 if (ReadMapKey(attr_map
, kAttrEnterpriseMode
, &mode
))
485 registration_mode_
= GetDeviceModeFromString(mode
);
486 } else if (ReadMapKey(attr_map
,
487 kAttrConsumerKioskEnabled
,
488 &consumer_kiosk_enabled
) &&
489 consumer_kiosk_enabled
== "true") {
490 registration_mode_
= DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH
;
491 } else if (enterprise_user
.empty() && enterprise_owned
!= "true") {
492 // |registration_user_| is empty on consumer devices.
493 registration_mode_
= DEVICE_MODE_CONSUMER
;
497 } // namespace policy