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