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