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
ReadMapKey(const std::map<std::string,std::string> & map,const std::string & key,std::string * value)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
GetEnterpriseOwnedInstallAttributesBlobForTesting(const std::string & user_name)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
EnterpriseInstallAttributes(chromeos::CryptohomeClient * cryptohome_client)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
~EnterpriseInstallAttributes()64 EnterpriseInstallAttributes::~EnterpriseInstallAttributes() {}
65
ReadCacheFile(const base::FilePath & cache_file)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
ReadImmutableAttributes(const base::Closure & callback)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
ReadAttributesIfReady(const base::Closure & callback,chromeos::DBusMethodCallStatus call_status,bool result)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
LockDevice(const std::string & user,DeviceMode device_mode,const std::string & device_id,const LockResultCallback & callback)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
LockDeviceIfAttributesIsReady(const std::string & user,DeviceMode device_mode,const std::string & device_id,const LockResultCallback & callback,chromeos::DBusMethodCallStatus call_status,bool result)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
OnReadImmutableAttributes(const std::string & registration_user,const LockResultCallback & callback)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
IsEnterpriseDevice()266 bool EnterpriseInstallAttributes::IsEnterpriseDevice() {
267 return device_locked_ && !registration_user_.empty();
268 }
269
IsConsumerKioskDeviceWithAutoLaunch()270 bool EnterpriseInstallAttributes::IsConsumerKioskDeviceWithAutoLaunch() {
271 return device_locked_ &&
272 registration_mode_ == DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH;
273 }
274
GetRegistrationUser()275 std::string EnterpriseInstallAttributes::GetRegistrationUser() {
276 if (!device_locked_)
277 return std::string();
278
279 return registration_user_;
280 }
281
GetDomain()282 std::string EnterpriseInstallAttributes::GetDomain() {
283 if (!IsEnterpriseDevice())
284 return std::string();
285
286 return registration_domain_;
287 }
288
GetDeviceId()289 std::string EnterpriseInstallAttributes::GetDeviceId() {
290 if (!IsEnterpriseDevice())
291 return std::string();
292
293 return registration_device_id_;
294 }
295
GetMode()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
GetDeviceModeString(DeviceMode mode)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
GetDeviceModeFromString(const std::string & mode)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
DecodeInstallAttributes(const std::map<std::string,std::string> & attr_map)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, ®istration_domain_))
376 registration_domain_ = gaia::CanonicalizeDomain(registration_domain_);
377 else
378 registration_domain_ = gaia::ExtractDomainName(registration_user_);
379
380 ReadMapKey(attr_map, kAttrEnterpriseDeviceId, ®istration_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