Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / chromeos / policy / enterprise_install_attributes.cc
blob5e0db82d6ba15beb0f8f96ff462718f8a4085ff9
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"
7 #include <utility>
9 #include "base/bind.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"
22 namespace policy {
24 namespace cryptohome_util = chromeos::cryptohome_util;
26 namespace {
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,
36 std::string* value) {
37 std::map<std::string, std::string>::const_iterator entry = map.find(key);
38 if (entry == map.end())
39 return false;
41 *value = entry->second;
42 return true;
45 } // namespace
47 // static
48 std::string
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))
85 return;
87 device_locked_ = true;
89 char buf[16384];
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();
93 return;
96 cryptohome::SerializedInstallAttributes install_attrs_proto;
97 if (!install_attrs_proto.ParseFromArray(buf, len)) {
98 LOG(ERROR) << "Failed to parse install attributes cache";
99 return;
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();
107 ++entry) {
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_) {
120 callback.Run();
121 return;
124 cryptohome_client_->InstallAttributesIsReady(
125 base::Bind(&EnterpriseInstallAttributes::ReadAttributesIfReady,
126 weak_ptr_factory_.GetWeakPtr(),
127 callback));
130 void EnterpriseInstallAttributes::ReadAttributesIfReady(
131 const base::Closure& callback,
132 chromeos::DBusMethodCallStatus call_status,
133 bool result) {
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,
143 kAttrEnterpriseMode,
144 kAttrEnterpriseOwned,
145 kAttrEnterpriseUser,
146 kAttrConsumerKioskEnabled,
148 std::map<std::string, std::string> attr_map;
149 for (size_t i = 0; i < arraysize(kEnterpriseAttributes); ++i) {
150 std::string value;
151 if (cryptohome_util::InstallAttributesGet(kEnterpriseAttributes[i],
152 &value))
153 attr_map[kEnterpriseAttributes[i]] = value;
156 DecodeInstallAttributes(attr_map);
159 callback.Run();
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);
176 return;
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);
186 return;
188 break;
190 case DEVICE_MODE_NOT_SET:
191 case DEVICE_MODE_PENDING:
192 // This case can't happen due to the CHECK_NE asserts above.
193 NOTREACHED();
194 break;
195 case DEVICE_MODE_CONSUMER:
196 case DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH:
197 // The user parameter is ignored for consumer devices.
198 break;
201 // Already locked in the right mode, signal success.
202 callback.Run(LOCK_SUCCESS);
203 return;
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(),
213 user,
214 device_mode,
215 device_id,
216 callback);
217 return;
220 device_lock_running_ = true;
221 cryptohome_client_->InstallAttributesIsReady(
222 base::Bind(&EnterpriseInstallAttributes::LockDeviceIfAttributesIsReady,
223 weak_ptr_factory_.GetWeakPtr(),
224 user,
225 device_mode,
226 device_id,
227 callback));
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,
236 bool result) {
237 if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS || !result) {
238 device_lock_running_ = false;
239 callback.Run(LOCK_NOT_READY);
240 return;
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);
255 return;
258 if (!cryptohome_util::InstallAttributesIsFirstInstall()) {
259 LOG(ERROR) << "Install attributes already installed.";
260 device_lock_running_ = false;
261 callback.Run(LOCK_ALREADY_LOCKED);
262 return;
265 std::string mode = GetDeviceModeString(device_mode);
266 std::string registration_user;
267 if (!user.empty())
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,
273 "true")) {
274 LOG(ERROR) << "Failed writing attributes.";
275 device_lock_running_ = false;
276 callback.Run(LOCK_SET_ERROR);
277 return;
279 } else {
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,
286 domain) ||
287 !cryptohome_util::InstallAttributesSet(kAttrEnterpriseMode, mode) ||
288 !cryptohome_util::InstallAttributesSet(kAttrEnterpriseDeviceId,
289 device_id)) {
290 LOG(ERROR) << "Failed writing attributes.";
291 device_lock_running_ = false;
292 callback.Run(LOCK_SET_ERROR);
293 return;
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);
302 return;
305 ReadImmutableAttributes(
306 base::Bind(&EnterpriseInstallAttributes::OnReadImmutableAttributes,
307 weak_ptr_factory_.GetWeakPtr(),
308 registration_user,
309 callback));
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);
320 return;
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() {
337 if (!device_locked_)
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(),
366 dbus_retries));
369 void EnterpriseInstallAttributes::OnTpmOwnerCheckCompleted(
370 int dbus_retries_remaining,
371 chromeos::DBusMethodCallStatus call_status,
372 bool result) {
373 if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS &&
374 dbus_retries_remaining) {
375 base::MessageLoop::current()->PostDelayedTask(
376 FROM_HERE,
377 base::Bind(&EnterpriseInstallAttributes::TriggerConsistencyCheck,
378 weak_ptr_factory_.GetWeakPtr(),
379 dbus_retries_remaining - 1),
380 base::TimeDelta::FromSeconds(kDbusRetryIntervalInSeconds));
381 return;
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;
388 else
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[] =
409 "consumer_kiosk";
410 const char EnterpriseInstallAttributes::kUnknownDeviceMode[] = "unknown";
412 const char EnterpriseInstallAttributes::kAttrEnterpriseDeviceId[] =
413 "enterprise.device_id";
414 const char EnterpriseInstallAttributes::kAttrEnterpriseDomain[] =
415 "enterprise.domain";
416 const char EnterpriseInstallAttributes::kAttrEnterpriseMode[] =
417 "enterprise.mode";
418 const char EnterpriseInstallAttributes::kAttrEnterpriseOwned[] =
419 "enterprise.owned";
420 const char EnterpriseInstallAttributes::kAttrEnterpriseUser[] =
421 "enterprise.user";
422 const char EnterpriseInstallAttributes::kAttrConsumerKioskEnabled[] =
423 "consumer.app_kiosk_enabled";
425 std::string EnterpriseInstallAttributes::GetDeviceModeString(DeviceMode mode) {
426 switch (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:
437 break;
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, &registration_domain_))
477 registration_domain_ = gaia::CanonicalizeDomain(registration_domain_);
478 else
479 registration_domain_ = gaia::ExtractDomainName(registration_user_);
481 ReadMapKey(attr_map, kAttrEnterpriseDeviceId, &registration_device_id_);
483 std::string mode;
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