enterprise_install_attributes.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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
19namespace policy {
20
21namespace cryptohome_util = chromeos::cryptohome_util;
22
23namespace {
24
25// Translates DeviceMode constants to strings used in the lockbox.
26std::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.
45DeviceMode 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
59bool 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
72const char EnterpriseInstallAttributes::kConsumerDeviceMode[] = "consumer";
73const char EnterpriseInstallAttributes::kEnterpiseDeviceMode[] = "enterprise";
74const char EnterpriseInstallAttributes::kRetailKioskDeviceMode[] = "kiosk";
75const char EnterpriseInstallAttributes::kConsumerKioskDeviceMode[] =
76    "consumer_kiosk";
77const char EnterpriseInstallAttributes::kUnknownDeviceMode[] = "unknown";
78
79const char EnterpriseInstallAttributes::kAttrEnterpriseDeviceId[] =
80    "enterprise.device_id";
81const char EnterpriseInstallAttributes::kAttrEnterpriseDomain[] =
82    "enterprise.domain";
83const char EnterpriseInstallAttributes::kAttrEnterpriseMode[] =
84    "enterprise.mode";
85const char EnterpriseInstallAttributes::kAttrEnterpriseOwned[] =
86    "enterprise.owned";
87const char EnterpriseInstallAttributes::kAttrEnterpriseUser[] =
88    "enterprise.user";
89const char EnterpriseInstallAttributes::kAttrConsumerKioskEnabled[] =
90    "consumer.app_kiosk_enabled";
91
92EnterpriseInstallAttributes::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
100EnterpriseInstallAttributes::~EnterpriseInstallAttributes() {}
101
102void 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
137void 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
150void 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
182void 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
214void 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
289void 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
302bool EnterpriseInstallAttributes::IsEnterpriseDevice() {
303  return device_locked_ && !registration_user_.empty();
304}
305
306bool EnterpriseInstallAttributes::IsConsumerKioskDeviceWithAutoLaunch() {
307  return device_locked_ &&
308         registration_mode_ == DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH;
309}
310
311std::string EnterpriseInstallAttributes::GetRegistrationUser() {
312  if (!device_locked_)
313    return std::string();
314
315  return registration_user_;
316}
317
318std::string EnterpriseInstallAttributes::GetDomain() {
319  if (!IsEnterpriseDevice())
320    return std::string();
321
322  return registration_domain_;
323}
324
325std::string EnterpriseInstallAttributes::GetDeviceId() {
326  if (!IsEnterpriseDevice())
327    return std::string();
328
329  return registration_device_id_;
330}
331
332DeviceMode EnterpriseInstallAttributes::GetMode() {
333  return registration_mode_;
334}
335
336void 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