Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / ownership / owner_settings_service.cc
index 0fc5bf9..a8fc0f2 100644 (file)
@@ -7,15 +7,17 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/login/users/user.h"
-#include "chrome/browser/chromeos/login/users/user_manager.h"
 #include "chrome/browser/chromeos/ownership/owner_settings_service_factory.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/chromeos/settings/session_manager_operation.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
+#include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "crypto/nss_util.h"
 #include "crypto/nss_util_internal.h"
@@ -34,6 +36,36 @@ namespace {
 scoped_refptr<OwnerKeyUtil>* g_owner_key_util_for_testing = NULL;
 DeviceSettingsService* g_device_settings_service_for_testing = NULL;
 
+// Assembles PolicyData based on |settings|, |policy_data| and
+// |user_id|.
+scoped_ptr<em::PolicyData> AssemblePolicy(
+    const std::string& user_id,
+    const em::PolicyData* policy_data,
+    const em::ChromeDeviceSettingsProto* settings) {
+  scoped_ptr<em::PolicyData> policy(new em::PolicyData());
+  if (policy_data) {
+    // Preserve management settings.
+    if (policy_data->has_management_mode())
+      policy->set_management_mode(policy_data->management_mode());
+    if (policy_data->has_request_token())
+      policy->set_request_token(policy_data->request_token());
+    if (policy_data->has_device_id())
+      policy->set_device_id(policy_data->device_id());
+  } else {
+    // If there's no previous policy data, this is the first time the device
+    // setting is set. We set the management mode to NOT_MANAGED initially.
+    policy->set_management_mode(em::PolicyData::NOT_MANAGED);
+  }
+  policy->set_policy_type(policy::dm_protocol::kChromeDevicePolicyType);
+  policy->set_timestamp(
+      (base::Time::Now() - base::Time::UnixEpoch()).InMilliseconds());
+  policy->set_username(user_id);
+  if (!settings->SerializeToString(policy->mutable_policy_value()))
+    return scoped_ptr<em::PolicyData>();
+
+  return policy.Pass();
+}
+
 std::string AssembleAndSignPolicy(scoped_ptr<em::PolicyData> policy,
                                   crypto::RSAPrivateKey* private_key) {
   // Assemble the policy.
@@ -64,30 +96,37 @@ std::string AssembleAndSignPolicy(scoped_ptr<em::PolicyData> policy,
 
 void LoadPrivateKeyByPublicKey(
     const scoped_refptr<OwnerKeyUtil>& owner_key_util,
-    const std::vector<uint8>& public_key,
+    scoped_refptr<PublicKey> public_key,
     const std::string& username_hash,
-    const base::Callback<void(scoped_ptr<crypto::RSAPrivateKey>)>& callback) {
+    const base::Callback<void(scoped_refptr<PublicKey> public_key,
+                              scoped_refptr<PrivateKey> private_key)>&
+        callback) {
   crypto::EnsureNSSInit();
   crypto::ScopedPK11Slot slot =
       crypto::GetPublicSlotForChromeOSUser(username_hash);
-  scoped_ptr<crypto::RSAPrivateKey> key(
-      owner_key_util->FindPrivateKeyInSlot(public_key, slot.get()));
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE, base::Bind(callback, base::Passed(&key)));
+  scoped_refptr<PrivateKey> private_key(new PrivateKey(
+      owner_key_util->FindPrivateKeyInSlot(public_key->data(), slot.get())));
+  BrowserThread::PostTask(BrowserThread::UI,
+                          FROM_HERE,
+                          base::Bind(callback, public_key, private_key));
 }
 
-void LoadPrivateKey(
-    const scoped_refptr<OwnerKeyUtil>& owner_key_util,
-    const std::string username_hash,
-    const base::Callback<void(scoped_ptr<crypto::RSAPrivateKey>)>& callback) {
-  std::vector<uint8> public_key;
-  if (!owner_key_util->ImportPublicKey(&public_key)) {
-    scoped_ptr<crypto::RSAPrivateKey> result;
+void LoadPrivateKey(const scoped_refptr<OwnerKeyUtil>& owner_key_util,
+                    const std::string username_hash,
+                    const base::Callback<void(
+                        scoped_refptr<PublicKey> public_key,
+                        scoped_refptr<PrivateKey> private_key)>& callback) {
+  std::vector<uint8> public_key_data;
+  scoped_refptr<PublicKey> public_key;
+  if (!owner_key_util->ImportPublicKey(&public_key_data)) {
+    scoped_refptr<PrivateKey> private_key;
     BrowserThread::PostTask(BrowserThread::UI,
                             FROM_HERE,
-                            base::Bind(callback, base::Passed(&result)));
+                            base::Bind(callback, public_key, private_key));
     return;
   }
+  public_key = new PublicKey();
+  public_key->data().swap(public_key_data);
   bool rv = BrowserThread::PostTask(BrowserThread::IO,
                                     FROM_HERE,
                                     base::Bind(&LoadPrivateKeyByPublicKey,
@@ -103,7 +142,7 @@ void LoadPrivateKey(
   }
 }
 
-bool IsPrivateKeyExistAsyncHelper(
+bool DoesPrivateKeyExistAsyncHelper(
     const scoped_refptr<OwnerKeyUtil>& owner_key_util) {
   std::vector<uint8> public_key;
   if (!owner_key_util->ImportPublicKey(&public_key))
@@ -114,6 +153,66 @@ bool IsPrivateKeyExistAsyncHelper(
   return is_owner;
 }
 
+// Checks whether NSS slots with private key are mounted or
+// not. Responds via |callback|.
+void DoesPrivateKeyExistAsync(
+    const OwnerSettingsService::IsOwnerCallback& callback) {
+  scoped_refptr<OwnerKeyUtil> owner_key_util;
+  if (g_owner_key_util_for_testing)
+    owner_key_util = *g_owner_key_util_for_testing;
+  else
+    owner_key_util = OwnerKeyUtil::Create();
+  scoped_refptr<base::TaskRunner> task_runner =
+      content::BrowserThread::GetBlockingPool()
+          ->GetTaskRunnerWithShutdownBehavior(
+              base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+  base::PostTaskAndReplyWithResult(
+      task_runner.get(),
+      FROM_HERE,
+      base::Bind(&DoesPrivateKeyExistAsyncHelper, owner_key_util),
+      callback);
+}
+
+// Returns the current management mode.
+em::PolicyData::ManagementMode GetManagementMode(
+    DeviceSettingsService* service) {
+  if (!service) {
+    LOG(ERROR) << "DeviceSettingsService is not initialized";
+    return em::PolicyData::NOT_MANAGED;
+  }
+
+  const em::PolicyData* policy_data = service->policy_data();
+  if (policy_data && policy_data->has_management_mode())
+    return policy_data->management_mode();
+  return em::PolicyData::NOT_MANAGED;
+}
+
+// Returns true if it is okay to transfer from the current mode to the new
+// mode. This function should be called in SetManagementMode().
+bool CheckManagementModeTransition(em::PolicyData::ManagementMode current_mode,
+                                   em::PolicyData::ManagementMode new_mode) {
+  // Mode is not changed.
+  if (current_mode == new_mode)
+    return true;
+
+  switch (current_mode) {
+    case em::PolicyData::NOT_MANAGED:
+      // For consumer management enrollment.
+      return new_mode == em::PolicyData::CONSUMER_MANAGED;
+
+    case em::PolicyData::ENTERPRISE_MANAGED:
+      // Management mode cannot be set when it is currently ENTERPRISE_MANAGED.
+      return false;
+
+    case em::PolicyData::CONSUMER_MANAGED:
+      // For consumer management unenrollment.
+      return new_mode == em::PolicyData::NOT_MANAGED;
+  }
+
+  NOTREACHED();
+  return false;
+}
+
 }  // namespace
 
 OwnerSettingsService::OwnerSettingsService(Profile* profile)
@@ -164,7 +263,7 @@ void OwnerSettingsService::IsOwnerAsync(const IsOwnerCallback& callback) {
 }
 
 bool OwnerSettingsService::AssembleAndSignPolicyAsync(
-    scoped_ptr<enterprise_management::PolicyData> policy,
+    scoped_ptr<em::PolicyData> policy,
     const AssembleAndSignPolicyCallback& callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (!IsOwner())
@@ -178,6 +277,49 @@ bool OwnerSettingsService::AssembleAndSignPolicyAsync(
   return true;
 }
 
+void OwnerSettingsService::SignAndStoreAsync(
+    scoped_ptr<em::ChromeDeviceSettingsProto> settings,
+    const base::Closure& callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  scoped_ptr<em::PolicyData> policy = AssemblePolicy(
+      user_id_, GetDeviceSettingsService()->policy_data(), settings.get());
+  if (!policy) {
+    HandleError(DeviceSettingsService::STORE_POLICY_ERROR, callback);
+    return;
+  }
+
+  EnqueueSignAndStore(policy.Pass(), callback);
+}
+
+void OwnerSettingsService::SetManagementSettingsAsync(
+    em::PolicyData::ManagementMode management_mode,
+    const std::string& request_token,
+    const std::string& device_id,
+    const base::Closure& callback) {
+  em::PolicyData::ManagementMode current_mode =
+      GetManagementMode(GetDeviceSettingsService());
+  if (!CheckManagementModeTransition(current_mode, management_mode)) {
+    LOG(ERROR) << "Invalid management mode transition: current mode = "
+               << current_mode << ", new mode = " << management_mode;
+    HandleError(DeviceSettingsService::STORE_POLICY_ERROR, callback);
+    return;
+  }
+
+  DeviceSettingsService* service = GetDeviceSettingsService();
+  scoped_ptr<em::PolicyData> policy = AssemblePolicy(
+      user_id_, service->policy_data(), service->device_settings());
+  if (!policy) {
+    HandleError(DeviceSettingsService::STORE_POLICY_ERROR, callback);
+    return;
+  }
+
+  policy->set_management_mode(management_mode);
+  policy->set_request_token(request_token);
+  policy->set_device_id(device_id);
+
+  EnqueueSignAndStore(policy.Pass(), callback);
+}
+
 void OwnerSettingsService::Observe(
     int type,
     const content::NotificationSource& source,
@@ -214,22 +356,22 @@ void OwnerSettingsService::OwnerKeySet(bool success) {
 }
 
 // static
-void OwnerSettingsService::IsPrivateKeyExistAsync(
+void OwnerSettingsService::IsOwnerForSafeModeAsync(
+    const std::string& user_id,
+    const std::string& user_hash,
     const IsOwnerCallback& callback) {
-  scoped_refptr<OwnerKeyUtil> owner_key_util;
-  if (g_owner_key_util_for_testing)
-    owner_key_util = *g_owner_key_util_for_testing;
-  else
-    owner_key_util = OwnerKeyUtil::Create();
-  scoped_refptr<base::TaskRunner> task_runner =
-      content::BrowserThread::GetBlockingPool()
-          ->GetTaskRunnerWithShutdownBehavior(
-              base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
-  base::PostTaskAndReplyWithResult(
-      task_runner.get(),
+  CHECK(chromeos::LoginState::Get()->IsInSafeMode());
+
+  // Make sure NSS is initialized and NSS DB is loaded for the user before
+  // searching for the owner key.
+  BrowserThread::PostTaskAndReply(
+      BrowserThread::IO,
       FROM_HERE,
-      base::Bind(&IsPrivateKeyExistAsyncHelper, owner_key_util),
-      callback);
+      base::Bind(base::IgnoreResult(&crypto::InitializeNSSForChromeOSUser),
+                 user_id,
+                 user_hash,
+                 ProfileHelper::GetProfilePathByUserIdHash(user_hash)),
+      base::Bind(&DoesPrivateKeyExistAsync, callback));
 }
 
 // static
@@ -271,13 +413,15 @@ void OwnerSettingsService::ReloadPrivateKey() {
 }
 
 void OwnerSettingsService::OnPrivateKeyLoaded(
-    scoped_ptr<crypto::RSAPrivateKey> private_key) {
+    scoped_refptr<PublicKey> public_key,
+    scoped_refptr<PrivateKey> private_key) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  private_key_ = new PrivateKey(private_key.release());
+  public_key_ = public_key;
+  private_key_ = private_key;
 
-  const std::string& user_id = profile_->GetProfileName();
-  if (user_id == OwnerSettingsServiceFactory::GetInstance()->GetUsername())
-    GetDeviceSettingsService()->InitOwner(user_id, weak_factory_.GetWeakPtr());
+  user_id_ = profile_->GetProfileName();
+  if (user_id_ == OwnerSettingsServiceFactory::GetInstance()->GetUsername())
+    GetDeviceSettingsService()->InitOwner(user_id_, weak_factory_.GetWeakPtr());
 
   std::vector<IsOwnerCallback> is_owner_callbacks;
   is_owner_callbacks.swap(pending_is_owner_callbacks_);
@@ -289,6 +433,68 @@ void OwnerSettingsService::OnPrivateKeyLoaded(
   }
 }
 
+void OwnerSettingsService::EnqueueSignAndStore(
+    scoped_ptr<em::PolicyData> policy,
+    const base::Closure& callback) {
+  SignAndStoreSettingsOperation* operation = new SignAndStoreSettingsOperation(
+      base::Bind(&OwnerSettingsService::HandleCompletedOperation,
+                 weak_factory_.GetWeakPtr(),
+                 callback),
+      policy.Pass());
+  operation->set_delegate(weak_factory_.GetWeakPtr());
+  pending_operations_.push_back(operation);
+  if (pending_operations_.front() == operation)
+    StartNextOperation();
+}
+
+void OwnerSettingsService::StartNextOperation() {
+  DeviceSettingsService* service = GetDeviceSettingsService();
+  if (!pending_operations_.empty() && service &&
+      service->session_manager_client()) {
+    pending_operations_.front()->Start(
+        service->session_manager_client(), GetOwnerKeyUtil(), public_key_);
+  }
+}
+
+void OwnerSettingsService::HandleCompletedOperation(
+    const base::Closure& callback,
+    SessionManagerOperation* operation,
+    DeviceSettingsService::Status status) {
+  DCHECK_EQ(operation, pending_operations_.front());
+
+  DeviceSettingsService* service = GetDeviceSettingsService();
+  if (status == DeviceSettingsService::STORE_SUCCESS) {
+    service->set_policy_data(operation->policy_data().Pass());
+    service->set_device_settings(operation->device_settings().Pass());
+  }
+
+  if ((operation->public_key() && !public_key_) ||
+      (operation->public_key() && public_key_ &&
+       operation->public_key()->data() != public_key_->data())) {
+    // Public part changed so we need to reload private part too.
+    ReloadPrivateKey();
+    content::NotificationService::current()->Notify(
+        chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
+        content::Source<OwnerSettingsService>(this),
+        content::NotificationService::NoDetails());
+  }
+  service->OnSignAndStoreOperationCompleted(status);
+  if (!callback.is_null())
+    callback.Run();
+
+  pending_operations_.pop_front();
+  delete operation;
+  StartNextOperation();
+}
+
+void OwnerSettingsService::HandleError(DeviceSettingsService::Status status,
+                                       const base::Closure& callback) {
+  LOG(ERROR) << "Session manager operation failed: " << status;
+  GetDeviceSettingsService()->OnSignAndStoreOperationCompleted(status);
+  if (!callback.is_null())
+    callback.Run();
+}
+
 scoped_refptr<OwnerKeyUtil> OwnerSettingsService::GetOwnerKeyUtil() {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (g_owner_key_util_for_testing)