#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"
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.
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,
}
}
-bool IsPrivateKeyExistAsyncHelper(
+bool DoesPrivateKeyExistAsyncHelper(
const scoped_refptr<OwnerKeyUtil>& owner_key_util) {
std::vector<uint8> public_key;
if (!owner_key_util->ImportPublicKey(&public_key))
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)
}
bool OwnerSettingsService::AssembleAndSignPolicyAsync(
- scoped_ptr<enterprise_management::PolicyData> policy,
+ scoped_ptr<em::PolicyData> policy,
const AssembleAndSignPolicyCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!IsOwner())
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,
}
// 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
}
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_);
}
}
+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)