enterprise_install_attributes.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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
19namespace policy {
20
21namespace cryptohome_util = chromeos::cryptohome_util;
22
23namespace {
24
25bool 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
39std::string
40EnterpriseInstallAttributes::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
56EnterpriseInstallAttributes::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
64EnterpriseInstallAttributes::~EnterpriseInstallAttributes() {}
65
66void 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
101void 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
114void 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
146void 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
178void 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_WRONG_USER);
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
253void 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
266bool EnterpriseInstallAttributes::IsEnterpriseDevice() {
267  return device_locked_ && !registration_user_.empty();
268}
269
270bool EnterpriseInstallAttributes::IsConsumerKioskDeviceWithAutoLaunch() {
271  return device_locked_ &&
272         registration_mode_ == DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH;
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
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.
304const char EnterpriseInstallAttributes::kConsumerDeviceMode[] = "consumer";
305const char EnterpriseInstallAttributes::kEnterpriseDeviceMode[] = "enterprise";
306const char EnterpriseInstallAttributes::kRetailKioskDeviceMode[] = "kiosk";
307const char EnterpriseInstallAttributes::kConsumerKioskDeviceMode[] =
308    "consumer_kiosk";
309const char EnterpriseInstallAttributes::kUnknownDeviceMode[] = "unknown";
310
311const char EnterpriseInstallAttributes::kAttrEnterpriseDeviceId[] =
312    "enterprise.device_id";
313const char EnterpriseInstallAttributes::kAttrEnterpriseDomain[] =
314    "enterprise.domain";
315const char EnterpriseInstallAttributes::kAttrEnterpriseMode[] =
316    "enterprise.mode";
317const char EnterpriseInstallAttributes::kAttrEnterpriseOwned[] =
318    "enterprise.owned";
319const char EnterpriseInstallAttributes::kAttrEnterpriseUser[] =
320    "enterprise.user";
321const char EnterpriseInstallAttributes::kAttrConsumerKioskEnabled[] =
322    "consumer.app_kiosk_enabled";
323
324std::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
342DeviceMode 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
356void 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