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