Home | History | Annotate | Download | only in policy
      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 
     19 namespace policy {
     20 
     21 namespace {
     22 
     23 // Translates DeviceMode constants to strings used in the lockbox.
     24 std::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.
     43 DeviceMode 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 
     57 bool 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 
     70 const char EnterpriseInstallAttributes::kConsumerDeviceMode[] = "consumer";
     71 const char EnterpriseInstallAttributes::kEnterpiseDeviceMode[] = "enterprise";
     72 const char EnterpriseInstallAttributes::kRetailKioskDeviceMode[] = "kiosk";
     73 const char EnterpriseInstallAttributes::kConsumerKioskDeviceMode[] =
     74     "consumer_kiosk";
     75 const char EnterpriseInstallAttributes::kUnknownDeviceMode[] = "unknown";
     76 
     77 const char EnterpriseInstallAttributes::kAttrEnterpriseDeviceId[] =
     78     "enterprise.device_id";
     79 const char EnterpriseInstallAttributes::kAttrEnterpriseDomain[] =
     80     "enterprise.domain";
     81 const char EnterpriseInstallAttributes::kAttrEnterpriseMode[] =
     82     "enterprise.mode";
     83 const char EnterpriseInstallAttributes::kAttrEnterpriseOwned[] =
     84     "enterprise.owned";
     85 const char EnterpriseInstallAttributes::kAttrEnterpriseUser[] =
     86     "enterprise.user";
     87 const char EnterpriseInstallAttributes::kAttrConsumerKioskEnabled[] =
     88     "consumer.app_kiosk_enabled";
     89 
     90 EnterpriseInstallAttributes::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 
     99 EnterpriseInstallAttributes::~EnterpriseInstallAttributes() {}
    100 
    101 void 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 
    136 void 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 
    149 void 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 
    180 void 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 
    212 void 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 
    245   if (device_mode == DEVICE_MODE_CONSUMER_KIOSK) {
    246     // Set values in the InstallAttrs and lock it.
    247     if (!cryptohome_->InstallAttributesSet(kAttrConsumerKioskEnabled, "true")) {
    248       LOG(ERROR) << "Failed writing attributes";
    249       callback.Run(LOCK_BACKEND_ERROR);
    250       return;
    251     }
    252   } else {
    253     std::string domain = gaia::ExtractDomainName(user);
    254     // Set values in the InstallAttrs and lock it.
    255     if (!cryptohome_->InstallAttributesSet(kAttrEnterpriseOwned, "true") ||
    256         !cryptohome_->InstallAttributesSet(kAttrEnterpriseUser, user) ||
    257         !cryptohome_->InstallAttributesSet(kAttrEnterpriseDomain, domain) ||
    258         !cryptohome_->InstallAttributesSet(kAttrEnterpriseMode, mode) ||
    259         !cryptohome_->InstallAttributesSet(kAttrEnterpriseDeviceId,
    260                                            device_id)) {
    261       LOG(ERROR) << "Failed writing attributes";
    262       callback.Run(LOCK_BACKEND_ERROR);
    263       return;
    264     }
    265   }
    266 
    267   if (!cryptohome_->InstallAttributesFinalize() ||
    268       cryptohome_->InstallAttributesIsFirstInstall()) {
    269     LOG(ERROR) << "Failed locking.";
    270     callback.Run(LOCK_BACKEND_ERROR);
    271     return;
    272   }
    273 
    274   ReadImmutableAttributes(
    275       base::Bind(&EnterpriseInstallAttributes::OnReadImmutableAttributes,
    276                  weak_ptr_factory_.GetWeakPtr(),
    277                  user,
    278                  callback));
    279 }
    280 
    281 void EnterpriseInstallAttributes::OnReadImmutableAttributes(
    282     const std::string& user,
    283     const LockResultCallback& callback) {
    284 
    285   if (GetRegistrationUser() != user) {
    286     LOG(ERROR) << "Locked data doesn't match";
    287     callback.Run(LOCK_BACKEND_ERROR);
    288     return;
    289   }
    290 
    291   callback.Run(LOCK_SUCCESS);
    292 }
    293 
    294 bool EnterpriseInstallAttributes::IsEnterpriseDevice() {
    295   return device_locked_ && !registration_user_.empty();
    296 }
    297 
    298 bool EnterpriseInstallAttributes::IsConsumerKioskDevice() {
    299   return device_locked_ && registration_mode_ == DEVICE_MODE_CONSUMER_KIOSK;
    300 }
    301 
    302 std::string EnterpriseInstallAttributes::GetRegistrationUser() {
    303   if (!device_locked_)
    304     return std::string();
    305 
    306   return registration_user_;
    307 }
    308 
    309 std::string EnterpriseInstallAttributes::GetDomain() {
    310   if (!IsEnterpriseDevice())
    311     return std::string();
    312 
    313   return registration_domain_;
    314 }
    315 
    316 std::string EnterpriseInstallAttributes::GetDeviceId() {
    317   if (!IsEnterpriseDevice())
    318     return std::string();
    319 
    320   return registration_device_id_;
    321 }
    322 
    323 DeviceMode EnterpriseInstallAttributes::GetMode() {
    324   return registration_mode_;
    325 }
    326 
    327 void EnterpriseInstallAttributes::DecodeInstallAttributes(
    328     const std::map<std::string, std::string>& attr_map) {
    329   std::string enterprise_owned;
    330   std::string enterprise_user;
    331   std::string consumer_kiosk_enabled;
    332   if (ReadMapKey(attr_map, kAttrEnterpriseOwned, &enterprise_owned) &&
    333       ReadMapKey(attr_map, kAttrEnterpriseUser, &enterprise_user) &&
    334       enterprise_owned == "true" &&
    335       !enterprise_user.empty()) {
    336     registration_user_ = gaia::CanonicalizeEmail(enterprise_user);
    337 
    338     // Initialize the mode to the legacy enterprise mode here and update
    339     // below if more information is present.
    340     registration_mode_ = DEVICE_MODE_ENTERPRISE;
    341 
    342     // If we could extract basic setting we should try to extract the
    343     // extended ones too. We try to set these to defaults as good as
    344     // as possible if present, which could happen for device enrolled in
    345     // pre 19 revisions of the code, before these new attributes were added.
    346     if (ReadMapKey(attr_map, kAttrEnterpriseDomain, &registration_domain_))
    347       registration_domain_ = gaia::CanonicalizeDomain(registration_domain_);
    348     else
    349       registration_domain_ = gaia::ExtractDomainName(registration_user_);
    350 
    351     ReadMapKey(attr_map, kAttrEnterpriseDeviceId, &registration_device_id_);
    352 
    353     std::string mode;
    354     if (ReadMapKey(attr_map, kAttrEnterpriseMode, &mode))
    355       registration_mode_ = GetDeviceModeFromString(mode);
    356   } else if (ReadMapKey(attr_map,
    357                         kAttrConsumerKioskEnabled,
    358                         &consumer_kiosk_enabled) &&
    359              consumer_kiosk_enabled == "true") {
    360     registration_mode_ = DEVICE_MODE_CONSUMER_KIOSK;
    361   } else if (enterprise_user.empty() && enterprise_owned != "true") {
    362     // |registration_user_| is empty on consumer devices.
    363     registration_mode_ = DEVICE_MODE_CONSUMER;
    364   }
    365 }
    366 
    367 }  // namespace policy
    368