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