• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/app_mode/kiosk_app_manager.h"
6 
7 #include <map>
8 #include <set>
9 
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "base/path_service.h"
13 #include "base/prefs/pref_registry_simple.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/prefs/scoped_user_pref_update.h"
16 #include "base/stl_util.h"
17 #include "base/sys_info.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/chromeos/app_mode/kiosk_app_data.h"
20 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h"
21 #include "chrome/browser/chromeos/login/user_manager.h"
22 #include "chrome/browser/chromeos/policy/device_local_account.h"
23 #include "chrome/browser/chromeos/settings/cros_settings.h"
24 #include "chrome/browser/chromeos/settings/owner_key_util.h"
25 #include "chrome/browser/policy/browser_policy_connector.h"
26 #include "chrome/common/chrome_paths.h"
27 #include "chromeos/cryptohome/async_method_caller.h"
28 #include "chromeos/settings/cros_settings_names.h"
29 #include "content/public/browser/browser_thread.h"
30 
31 namespace chromeos {
32 
33 namespace {
34 
35 // Domain that is used for kiosk-app account IDs.
36 const char kKioskAppAccountDomain[] = "kiosk-apps";
37 
GenerateKioskAppAccountId(const std::string & app_id)38 std::string GenerateKioskAppAccountId(const std::string& app_id) {
39   return app_id + '@' + kKioskAppAccountDomain;
40 }
41 
OnRemoveAppCryptohomeComplete(const std::string & app,bool success,cryptohome::MountError return_code)42 void OnRemoveAppCryptohomeComplete(const std::string& app,
43                                    bool success,
44                                    cryptohome::MountError return_code) {
45   if (!success) {
46     LOG(ERROR) << "Remove cryptohome for " << app
47         << " failed, return code: " << return_code;
48   }
49 }
50 
51 // Check for presence of machine owner public key file.
CheckOwnerFilePresence(bool * present)52 void CheckOwnerFilePresence(bool *present) {
53   scoped_refptr<OwnerKeyUtil> util = OwnerKeyUtil::Create();
54   *present = util->IsPublicKeyPresent();
55 }
56 
57 }  // namespace
58 
59 // static
60 const char KioskAppManager::kKioskDictionaryName[] = "kiosk";
61 const char KioskAppManager::kKeyApps[] = "apps";
62 const char KioskAppManager::kKeyAutoLoginState[] = "auto_login_state";
63 const char KioskAppManager::kIconCacheDir[] = "kiosk";
64 
65 // static
66 static base::LazyInstance<KioskAppManager> instance = LAZY_INSTANCE_INITIALIZER;
Get()67 KioskAppManager* KioskAppManager::Get() {
68   return instance.Pointer();
69 }
70 
71 // static
Shutdown()72 void KioskAppManager::Shutdown() {
73   if (instance == NULL)
74     return;
75 
76   instance.Pointer()->CleanUp();
77 }
78 
79 // static
RegisterPrefs(PrefRegistrySimple * registry)80 void KioskAppManager::RegisterPrefs(PrefRegistrySimple* registry) {
81   registry->RegisterDictionaryPref(kKioskDictionaryName);
82 }
83 
App(const KioskAppData & data)84 KioskAppManager::App::App(const KioskAppData& data)
85     : app_id(data.app_id()),
86       user_id(data.user_id()),
87       name(data.name()),
88       icon(data.icon()),
89       is_loading(data.IsLoading()) {
90 }
91 
App()92 KioskAppManager::App::App() : is_loading(false) {}
~App()93 KioskAppManager::App::~App() {}
94 
GetAutoLaunchApp() const95 std::string KioskAppManager::GetAutoLaunchApp() const {
96   return auto_launch_app_id_;
97 }
98 
SetAutoLaunchApp(const std::string & app_id)99 void KioskAppManager::SetAutoLaunchApp(const std::string& app_id) {
100   SetAutoLoginState(AUTOLOGIN_REQUESTED);
101   // Clean first, so the proper change callbacks are triggered even
102   // if we are only changing AutoLoginState here.
103   if (!auto_launch_app_id_.empty()) {
104     CrosSettings::Get()->SetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
105                                    std::string());
106   }
107 
108   CrosSettings::Get()->SetString(
109       kAccountsPrefDeviceLocalAccountAutoLoginId,
110       app_id.empty() ? std::string() : GenerateKioskAppAccountId(app_id));
111   CrosSettings::Get()->SetInteger(
112       kAccountsPrefDeviceLocalAccountAutoLoginDelay, 0);
113 }
114 
EnableConsumerModeKiosk(const KioskAppManager::EnableKioskModeCallback & callback)115 void KioskAppManager::EnableConsumerModeKiosk(
116     const KioskAppManager::EnableKioskModeCallback& callback) {
117   g_browser_process->browser_policy_connector()->GetInstallAttributes()->
118       LockDevice(std::string(),  // user
119                  policy::DEVICE_MODE_CONSUMER_KIOSK,
120                  std::string(),  // device_id
121                  base::Bind(&KioskAppManager::OnLockDevice,
122                             base::Unretained(this),
123                             callback));
124 }
125 
GetConsumerKioskModeStatus(const KioskAppManager::GetConsumerKioskModeStatusCallback & callback)126 void KioskAppManager::GetConsumerKioskModeStatus(
127     const KioskAppManager::GetConsumerKioskModeStatusCallback& callback) {
128   g_browser_process->browser_policy_connector()->GetInstallAttributes()->
129       ReadImmutableAttributes(
130           base::Bind(&KioskAppManager::OnReadImmutableAttributes,
131                      base::Unretained(this),
132                      callback));
133 }
134 
OnLockDevice(const KioskAppManager::EnableKioskModeCallback & callback,policy::EnterpriseInstallAttributes::LockResult result)135 void KioskAppManager::OnLockDevice(
136     const KioskAppManager::EnableKioskModeCallback& callback,
137     policy::EnterpriseInstallAttributes::LockResult result) {
138   if (callback.is_null())
139     return;
140 
141   callback.Run(result == policy::EnterpriseInstallAttributes::LOCK_SUCCESS);
142 }
143 
OnOwnerFileChecked(const KioskAppManager::GetConsumerKioskModeStatusCallback & callback,bool * owner_present)144 void KioskAppManager::OnOwnerFileChecked(
145     const KioskAppManager::GetConsumerKioskModeStatusCallback& callback,
146     bool* owner_present) {
147   ownership_established_ = *owner_present;
148 
149   if (callback.is_null())
150     return;
151 
152   // If we have owner already established on the machine, don't let
153   // consumer kiosk to be enabled.
154   if (ownership_established_)
155     callback.Run(CONSUMER_KIOSK_MODE_DISABLED);
156   else
157     callback.Run(CONSUMER_KIOSK_MODE_CONFIGURABLE);
158 }
159 
OnReadImmutableAttributes(const KioskAppManager::GetConsumerKioskModeStatusCallback & callback)160 void KioskAppManager::OnReadImmutableAttributes(
161     const KioskAppManager::GetConsumerKioskModeStatusCallback& callback) {
162   if (callback.is_null())
163     return;
164 
165   ConsumerKioskModeStatus status = CONSUMER_KIOSK_MODE_DISABLED;
166   policy::EnterpriseInstallAttributes* attributes =
167       g_browser_process->browser_policy_connector()->GetInstallAttributes();
168   switch (attributes->GetMode()) {
169     case policy::DEVICE_MODE_NOT_SET: {
170       if (!base::SysInfo::IsRunningOnChromeOS()) {
171         status = CONSUMER_KIOSK_MODE_CONFIGURABLE;
172       } else if (!ownership_established_) {
173         bool* owner_present = new bool(false);
174         content::BrowserThread::PostBlockingPoolTaskAndReply(
175             FROM_HERE,
176             base::Bind(&CheckOwnerFilePresence,
177                        owner_present),
178             base::Bind(&KioskAppManager::OnOwnerFileChecked,
179                        base::Unretained(this),
180                        callback,
181                        base::Owned(owner_present)));
182         return;
183       }
184       break;
185     }
186     case policy::DEVICE_MODE_CONSUMER_KIOSK:
187       status = CONSUMER_KIOSK_MODE_ENABLED;
188       break;
189     default:
190       break;
191   }
192 
193   callback.Run(status);
194 }
195 
SetEnableAutoLaunch(bool value)196 void KioskAppManager::SetEnableAutoLaunch(bool value) {
197   SetAutoLoginState(value ? AUTOLOGIN_APPROVED : AUTOLOGIN_REJECTED);
198 }
199 
IsAutoLaunchRequested() const200 bool KioskAppManager::IsAutoLaunchRequested() const {
201   if (GetAutoLaunchApp().empty())
202     return false;
203 
204   // Apps that were installed by the policy don't require machine owner
205   // consent through UI.
206   if (g_browser_process->browser_policy_connector()->IsEnterpriseManaged())
207     return false;
208 
209   return GetAutoLoginState() == AUTOLOGIN_REQUESTED;
210 }
211 
IsAutoLaunchEnabled() const212 bool KioskAppManager::IsAutoLaunchEnabled() const {
213   if (GetAutoLaunchApp().empty())
214     return false;
215 
216   // Apps that were installed by the policy don't require machine owner
217   // consent through UI.
218   if (g_browser_process->browser_policy_connector()->IsEnterpriseManaged())
219     return true;
220 
221   return GetAutoLoginState() == AUTOLOGIN_APPROVED;
222 }
223 
AddApp(const std::string & app_id)224 void KioskAppManager::AddApp(const std::string& app_id) {
225   std::vector<policy::DeviceLocalAccount> device_local_accounts =
226       policy::GetDeviceLocalAccounts(CrosSettings::Get());
227 
228   // Don't insert the app if it's already in the list.
229   for (std::vector<policy::DeviceLocalAccount>::const_iterator
230            it = device_local_accounts.begin();
231        it != device_local_accounts.end(); ++it) {
232     if (it->type == policy::DeviceLocalAccount::TYPE_KIOSK_APP &&
233         it->kiosk_app_id == app_id) {
234       return;
235     }
236   }
237 
238   // Add the new account.
239   device_local_accounts.push_back(policy::DeviceLocalAccount(
240       policy::DeviceLocalAccount::TYPE_KIOSK_APP,
241       GenerateKioskAppAccountId(app_id),
242       app_id));
243 
244   policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts);
245 }
246 
RemoveApp(const std::string & app_id)247 void KioskAppManager::RemoveApp(const std::string& app_id) {
248   // Resets auto launch app if it is the removed app.
249   if (auto_launch_app_id_ == app_id)
250     SetAutoLaunchApp(std::string());
251 
252   std::vector<policy::DeviceLocalAccount> device_local_accounts =
253       policy::GetDeviceLocalAccounts(CrosSettings::Get());
254   if (device_local_accounts.empty())
255     return;
256 
257   // Remove entries that match |app_id|.
258   for (std::vector<policy::DeviceLocalAccount>::iterator
259            it = device_local_accounts.begin();
260        it != device_local_accounts.end(); ++it) {
261     if (it->type == policy::DeviceLocalAccount::TYPE_KIOSK_APP &&
262         it->kiosk_app_id == app_id) {
263       device_local_accounts.erase(it);
264       break;
265     }
266   }
267 
268   policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts);
269 }
270 
GetApps(Apps * apps) const271 void KioskAppManager::GetApps(Apps* apps) const {
272   apps->clear();
273   apps->reserve(apps_.size());
274   for (size_t i = 0; i < apps_.size(); ++i)
275     apps->push_back(App(*apps_[i]));
276 }
277 
GetApp(const std::string & app_id,App * app) const278 bool KioskAppManager::GetApp(const std::string& app_id, App* app) const {
279   const KioskAppData* data = GetAppData(app_id);
280   if (!data)
281     return false;
282 
283   *app = App(*data);
284   return true;
285 }
286 
GetAppRawIcon(const std::string & app_id) const287 const base::RefCountedString* KioskAppManager::GetAppRawIcon(
288     const std::string& app_id) const {
289   const KioskAppData* data = GetAppData(app_id);
290   if (!data)
291     return NULL;
292 
293   return data->raw_icon();
294 }
295 
GetDisableBailoutShortcut() const296 bool KioskAppManager::GetDisableBailoutShortcut() const {
297   bool enable;
298   if (CrosSettings::Get()->GetBoolean(
299           kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, &enable)) {
300     return !enable;
301   }
302 
303   return false;
304 }
305 
ClearAppData(const std::string & app_id)306 void KioskAppManager::ClearAppData(const std::string& app_id) {
307   KioskAppData* app_data = GetAppDataMutable(app_id);
308   if (!app_data)
309     return;
310 
311   app_data->ClearCache();
312 }
313 
UpdateAppDataFromProfile(const std::string & app_id,Profile * profile,const extensions::Extension * app)314 void KioskAppManager::UpdateAppDataFromProfile(
315     const std::string& app_id,
316     Profile* profile,
317     const extensions::Extension* app) {
318   KioskAppData* app_data = GetAppDataMutable(app_id);
319   if (!app_data)
320     return;
321 
322   app_data->LoadFromInstalledApp(profile, app);
323 }
324 
AddObserver(KioskAppManagerObserver * observer)325 void KioskAppManager::AddObserver(KioskAppManagerObserver* observer) {
326   observers_.AddObserver(observer);
327 }
328 
RemoveObserver(KioskAppManagerObserver * observer)329 void KioskAppManager::RemoveObserver(KioskAppManagerObserver* observer) {
330   observers_.RemoveObserver(observer);
331 }
332 
KioskAppManager()333 KioskAppManager::KioskAppManager() : ownership_established_(false) {
334   UpdateAppData();
335   local_accounts_subscription_ =
336       CrosSettings::Get()->AddSettingsObserver(
337           kAccountsPrefDeviceLocalAccounts,
338           base::Bind(&KioskAppManager::UpdateAppData, base::Unretained(this)));
339   local_account_auto_login_id_subscription_ =
340       CrosSettings::Get()->AddSettingsObserver(
341           kAccountsPrefDeviceLocalAccountAutoLoginId,
342           base::Bind(&KioskAppManager::UpdateAppData, base::Unretained(this)));
343 }
344 
~KioskAppManager()345 KioskAppManager::~KioskAppManager() {}
346 
CleanUp()347 void KioskAppManager::CleanUp() {
348   local_accounts_subscription_.reset();
349   local_account_auto_login_id_subscription_.reset();
350   apps_.clear();
351 }
352 
GetAppData(const std::string & app_id) const353 const KioskAppData* KioskAppManager::GetAppData(
354     const std::string& app_id) const {
355   for (size_t i = 0; i < apps_.size(); ++i) {
356     const KioskAppData* data = apps_[i];
357     if (data->app_id() == app_id)
358       return data;
359   }
360 
361   return NULL;
362 }
363 
GetAppDataMutable(const std::string & app_id)364 KioskAppData* KioskAppManager::GetAppDataMutable(const std::string& app_id) {
365   return const_cast<KioskAppData*>(GetAppData(app_id));
366 }
367 
UpdateAppData()368 void KioskAppManager::UpdateAppData() {
369   // Gets app id to data mapping for existing apps.
370   std::map<std::string, KioskAppData*> old_apps;
371   for (size_t i = 0; i < apps_.size(); ++i)
372     old_apps[apps_[i]->app_id()] = apps_[i];
373   apps_.weak_clear();  // |old_apps| takes ownership
374 
375   auto_launch_app_id_.clear();
376   std::string auto_login_account_id;
377   CrosSettings::Get()->GetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
378                                  &auto_login_account_id);
379 
380   // Re-populates |apps_| and reuses existing KioskAppData when possible.
381   const std::vector<policy::DeviceLocalAccount> device_local_accounts =
382       policy::GetDeviceLocalAccounts(CrosSettings::Get());
383   for (std::vector<policy::DeviceLocalAccount>::const_iterator
384            it = device_local_accounts.begin();
385        it != device_local_accounts.end(); ++it) {
386     if (it->type != policy::DeviceLocalAccount::TYPE_KIOSK_APP)
387       continue;
388 
389     if (it->account_id == auto_login_account_id)
390       auto_launch_app_id_ = it->kiosk_app_id;
391 
392     // TODO(mnissler): Support non-CWS update URLs.
393 
394     std::map<std::string, KioskAppData*>::iterator old_it =
395         old_apps.find(it->kiosk_app_id);
396     if (old_it != old_apps.end()) {
397       apps_.push_back(old_it->second);
398       old_apps.erase(old_it);
399     } else {
400       KioskAppData* new_app =
401           new KioskAppData(this, it->kiosk_app_id, it->user_id);
402       apps_.push_back(new_app);  // Takes ownership of |new_app|.
403       new_app->Load();
404     }
405   }
406 
407   // Clears cache and deletes the remaining old data.
408   for (std::map<std::string, KioskAppData*>::iterator it = old_apps.begin();
409        it != old_apps.end(); ++it) {
410     it->second->ClearCache();
411     cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
412         it->second->user_id(),
413         base::Bind(&OnRemoveAppCryptohomeComplete, it->first));
414   }
415   STLDeleteValues(&old_apps);
416 
417   FOR_EACH_OBSERVER(KioskAppManagerObserver, observers_,
418                     OnKioskAppsSettingsChanged());
419 }
420 
GetKioskAppIconCacheDir(base::FilePath * cache_dir)421 void KioskAppManager::GetKioskAppIconCacheDir(base::FilePath* cache_dir) {
422   base::FilePath user_data_dir;
423   CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
424   *cache_dir = user_data_dir.AppendASCII(kIconCacheDir);
425 }
426 
OnKioskAppDataChanged(const std::string & app_id)427 void KioskAppManager::OnKioskAppDataChanged(const std::string& app_id) {
428   FOR_EACH_OBSERVER(KioskAppManagerObserver,
429                     observers_,
430                     OnKioskAppDataChanged(app_id));
431 }
432 
OnKioskAppDataLoadFailure(const std::string & app_id)433 void KioskAppManager::OnKioskAppDataLoadFailure(const std::string& app_id) {
434   FOR_EACH_OBSERVER(KioskAppManagerObserver,
435                     observers_,
436                     OnKioskAppDataLoadFailure(app_id));
437   RemoveApp(app_id);
438 }
439 
GetAutoLoginState() const440 KioskAppManager::AutoLoginState KioskAppManager::GetAutoLoginState() const {
441   PrefService* prefs = g_browser_process->local_state();
442   const base::DictionaryValue* dict =
443       prefs->GetDictionary(KioskAppManager::kKioskDictionaryName);
444   int value;
445   if (!dict->GetInteger(kKeyAutoLoginState, &value))
446     return AUTOLOGIN_NONE;
447 
448   return static_cast<AutoLoginState>(value);
449 }
450 
SetAutoLoginState(AutoLoginState state)451 void KioskAppManager::SetAutoLoginState(AutoLoginState state) {
452   PrefService* prefs = g_browser_process->local_state();
453   DictionaryPrefUpdate dict_update(prefs,
454                                    KioskAppManager::kKioskDictionaryName);
455   dict_update->SetInteger(kKeyAutoLoginState, state);
456   prefs->CommitPendingWrite();
457 }
458 
459 }  // namespace chromeos
460