// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/chromeos/login/signed_settings.h" #include <string> #include <vector> #include "base/memory/ref_counted.h" #include "base/stringprintf.h" #include "base/threading/thread_restrictions.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/cros/login_library.h" #include "chrome/browser/chromeos/cros_settings_names.h" #include "chrome/browser/chromeos/login/authenticator.h" #include "chrome/browser/chromeos/login/ownership_service.h" #include "chrome/browser/chromeos/login/signed_settings_temp_storage.h" #include "chrome/browser/policy/proto/chrome_device_policy.pb.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "content/browser/browser_thread.h" namespace chromeos { using google::protobuf::RepeatedPtrField; using std::string; // static const char SignedSettings::kDevicePolicyType[] = "google/chromeos/device"; SignedSettings::Relay::Relay(SignedSettings* s) : settings_(s) { } SignedSettings::Relay::~Relay() {} void SignedSettings::Relay::OnSettingsOpCompleted( SignedSettings::ReturnCode code, const em::PolicyFetchResponse& value) { if (code == SignedSettings::SUCCESS) { settings_->Execute(); return; } settings_->Fail(code); } SignedSettings::SignedSettings() : service_(OwnershipService::GetSharedInstance()), relay_(NULL), polfetcher_(NULL) { } SignedSettings::~SignedSettings() {} void SignedSettings::TryToFetchPolicyAndCallBack() { relay_.reset(new Relay(this)); polfetcher_ = SignedSettings::CreateRetrievePolicyOp(relay_.get()); polfetcher_->set_service(service_); polfetcher_->Execute(); } // static bool SignedSettings::PolicyIsSane(const em::PolicyFetchResponse& value, em::PolicyData* poldata) { if (value.has_policy_data()) { poldata->ParseFromString(value.policy_data()); if (poldata->has_policy_type() && poldata->policy_type() == kDevicePolicyType && poldata->has_policy_value()) { return true; } } return false; } // static SignedSettings::ReturnCode SignedSettings::MapKeyOpCode( OwnerManager::KeyOpCode return_code) { return (return_code == OwnerManager::KEY_UNAVAILABLE ? KEY_UNAVAILABLE : BAD_SIGNATURE); } // static bool SignedSettings::EnumerateWhitelist(std::vector<std::string>* whitelisted) { OwnershipService* service = OwnershipService::GetSharedInstance(); if (!service->has_cached_policy()) return false; em::ChromeDeviceSettingsProto pol; pol.ParseFromString(service->cached_policy().policy_value()); if (!pol.has_user_whitelist()) return false; const RepeatedPtrField<std::string>& whitelist = pol.user_whitelist().user_whitelist(); for (RepeatedPtrField<std::string>::const_iterator it = whitelist.begin(); it != whitelist.end(); ++it) { whitelisted->push_back(*it); } return true; } class CheckWhitelistOp : public SignedSettings { public: CheckWhitelistOp(const std::string& email, SignedSettings::Delegate<bool>* d); virtual ~CheckWhitelistOp(); void Execute(); void Fail(SignedSettings::ReturnCode code); void Succeed(bool value); // Implementation of OwnerManager::Delegate void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload); private: bool LookUpInPolicy(const std::string& email); // Always call d_->OnSettingOpCompleted() via this call. // It guarantees that the callback will not be triggered until _after_ // Execute() returns, which is implicitly assumed by SignedSettingsHelper // in some cases. void PerformCallback(SignedSettings::ReturnCode code, bool value); const std::string email_; SignedSettings::Delegate<bool>* d_; }; class WhitelistOp : public SignedSettings, public SignedSettings::Delegate<bool> { public: WhitelistOp(const std::string& email, bool add_to_whitelist, SignedSettings::Delegate<bool>* d); virtual ~WhitelistOp(); void Execute(); void Fail(SignedSettings::ReturnCode code); void Succeed(bool value); // Implementation of OwnerManager::Delegate void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload); // Implementation of SignedSettings::Delegate void OnSettingsOpCompleted(ReturnCode code, bool value); private: void ModifyWhitelist(const std::string& email, bool add_to_whitelist, em::UserWhitelistProto* whitelist_proto); // Always call d_->OnSettingOpCompleted() via this call. // It guarantees that the callback will not be triggered until _after_ // Execute() returns, which is implicitly assumed by SignedSettingsHelper // in some cases. void PerformCallback(SignedSettings::ReturnCode code, bool value); const std::string email_; const bool add_to_whitelist_; SignedSettings::Delegate<bool>* d_; em::PolicyFetchResponse to_store_; scoped_refptr<SignedSettings> store_op_; }; class StorePropertyOp : public SignedSettings, public SignedSettings::Delegate<bool> { public: StorePropertyOp(const std::string& name, const std::string& value, SignedSettings::Delegate<bool>* d); virtual ~StorePropertyOp(); void Execute(); void Fail(SignedSettings::ReturnCode code); void Succeed(bool value); // Implementation of OwnerManager::Delegate void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload); // Implementation of SignedSettings::Delegate void OnSettingsOpCompleted(ReturnCode code, bool value); private: void SetInPolicy(const std::string& prop, const std::string& value, em::PolicyData* poldata); // Always call d_->OnSettingOpCompleted() via this call. // It guarantees that the callback will not be triggered until _after_ // Execute() returns, which is implicitly assumed by SignedSettingsHelper // in some cases. void PerformCallback(SignedSettings::ReturnCode code, bool value); std::string name_; std::string value_; SignedSettings::Delegate<bool>* d_; em::PolicyFetchResponse to_store_; scoped_refptr<SignedSettings> store_op_; }; class RetrievePropertyOp : public SignedSettings { public: RetrievePropertyOp(const std::string& name, SignedSettings::Delegate<std::string>* d); virtual ~RetrievePropertyOp(); void Execute(); void Fail(SignedSettings::ReturnCode code); void Succeed(const std::string& value); // Implementation of OwnerManager::Delegate::OnKeyOpComplete() void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload); private: static const char* kVeritas[]; std::string LookUpInPolicy(const std::string& prop); // Always call d_->OnSettingOpCompleted() via this call. // It guarantees that the callback will not be triggered until _after_ // Execute() returns, which is implicitly assumed by SignedSettingsHelper // in some cases. void PerformCallback(SignedSettings::ReturnCode code, const std::string& value); std::string name_; std::string value_; SignedSettings::Delegate<std::string>* d_; }; class StorePolicyOp : public SignedSettings { public: StorePolicyOp(em::PolicyFetchResponse* policy, SignedSettings::Delegate<bool>* d); virtual ~StorePolicyOp(); void Execute(); void Fail(SignedSettings::ReturnCode code); void Succeed(bool value); // Implementation of OwnerManager::Delegate void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload); private: static void OnBoolComplete(void* delegate, bool success); // Always call d_->OnSettingOpCompleted() via this call. // It guarantees that the callback will not be triggered until _after_ // Execute() returns, which is implicitly assumed by SignedSettingsHelper // in some cases. void PerformCallback(SignedSettings::ReturnCode code, bool value); em::PolicyFetchResponse* policy_; SignedSettings::Delegate<bool>* d_; void RequestStorePolicy(); }; class RetrievePolicyOp : public SignedSettings { public: explicit RetrievePolicyOp( SignedSettings::Delegate<const em::PolicyFetchResponse&>* d); virtual ~RetrievePolicyOp(); void Execute(); void Fail(SignedSettings::ReturnCode code); void Succeed(const em::PolicyFetchResponse& value); // Implementation of OwnerManager::Delegate void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload); private: static void OnStringComplete(void* delegate, const char* policy, const unsigned int len); // Always call d_->OnSettingOpCompleted() via this call. // It guarantees that the callback will not be triggered until _after_ // Execute() returns, which is implicitly assumed by SignedSettingsHelper // in some cases. void PerformCallback(SignedSettings::ReturnCode code, const em::PolicyFetchResponse& value); void ProcessPolicy(const char* out, const unsigned int len); em::PolicyFetchResponse policy_; SignedSettings::Delegate<const em::PolicyFetchResponse&>* d_; }; // static SignedSettings* SignedSettings::CreateCheckWhitelistOp( const std::string& email, SignedSettings::Delegate<bool>* d) { DCHECK(d != NULL); return new CheckWhitelistOp(Authenticator::Canonicalize(email), d); } // static SignedSettings* SignedSettings::CreateWhitelistOp( const std::string& email, bool add_to_whitelist, SignedSettings::Delegate<bool>* d) { DCHECK(d != NULL); return new WhitelistOp(Authenticator::Canonicalize(email), add_to_whitelist, d); } // static SignedSettings* SignedSettings::CreateStorePropertyOp( const std::string& name, const std::string& value, SignedSettings::Delegate<bool>* d) { DCHECK(d != NULL); return new StorePropertyOp(name, value, d); } // static SignedSettings* SignedSettings::CreateRetrievePropertyOp( const std::string& name, SignedSettings::Delegate<std::string>* d) { DCHECK(d != NULL); return new RetrievePropertyOp(name, d); } // static SignedSettings* SignedSettings::CreateStorePolicyOp( em::PolicyFetchResponse* policy, SignedSettings::Delegate<bool>* d) { DCHECK(d != NULL); DCHECK(policy != NULL); return new StorePolicyOp(policy, d); } // static SignedSettings* SignedSettings::CreateRetrievePolicyOp( SignedSettings::Delegate<const em::PolicyFetchResponse&>* d) { DCHECK(d != NULL); return new RetrievePolicyOp(d); } CheckWhitelistOp::CheckWhitelistOp(const std::string& email, SignedSettings::Delegate<bool>* d) : email_(email), d_(d) { } CheckWhitelistOp::~CheckWhitelistOp() {} void CheckWhitelistOp::Execute() { CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded()); std::vector<uint8> sig; std::string email_to_check = email_; if (!service_->has_cached_policy()) { TryToFetchPolicyAndCallBack(); return; } if (LookUpInPolicy(email_to_check)) { VLOG(2) << "Whitelist check was successful for " << email_to_check; Succeed(true); return; } // If the exact match was not found try to match against a wildcard entry // where the domain only matches (e.g. *@example.com). In theory we should // always have correctly formated mail address here but a little precaution // does no harm. if (email_.find('@') != std::string::npos) { email_to_check = std::string("*").append(email_.substr(email_.find('@'))); if (LookUpInPolicy(email_to_check)) { VLOG(2) << "Whitelist check was successful for " << email_to_check; Succeed(true); return; } } Fail(NOT_FOUND); return; } void CheckWhitelistOp::Fail(SignedSettings::ReturnCode code) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &CheckWhitelistOp::PerformCallback, code, false)); } void CheckWhitelistOp::Succeed(bool value) { BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &CheckWhitelistOp::PerformCallback, SUCCESS, value)); } void CheckWhitelistOp::OnKeyOpComplete( const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload) { NOTREACHED(); // Ensure we're on the UI thread, due to the need to send DBus traffic. if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &CheckWhitelistOp::OnKeyOpComplete, return_code, payload)); return; } if (return_code == OwnerManager::SUCCESS) { VLOG(2) << "Whitelist check was successful."; Succeed(true); } else { VLOG(2) << "Whitelist check failed."; Fail(SignedSettings::MapKeyOpCode(return_code)); } } bool CheckWhitelistOp::LookUpInPolicy(const std::string& email) { em::ChromeDeviceSettingsProto pol; pol.ParseFromString(service_->cached_policy().policy_value()); if (!pol.has_user_whitelist()) return false; const RepeatedPtrField<std::string>& whitelist = pol.user_whitelist().user_whitelist(); for (RepeatedPtrField<std::string>::const_iterator it = whitelist.begin(); it != whitelist.end(); ++it) { if (email == *it) return true; } return false; } void CheckWhitelistOp::PerformCallback(SignedSettings::ReturnCode code, bool value) { d_->OnSettingsOpCompleted(code, value); } WhitelistOp::WhitelistOp(const std::string& email, bool add_to_whitelist, SignedSettings::Delegate<bool>* d) : email_(email), add_to_whitelist_(add_to_whitelist), d_(d) { } WhitelistOp::~WhitelistOp() {} void WhitelistOp::Execute() { if (!service_->has_cached_policy()) { TryToFetchPolicyAndCallBack(); return; } em::PolicyData to_sign; to_sign.CheckTypeAndMergeFrom(service_->cached_policy()); em::ChromeDeviceSettingsProto pol; pol.ParseFromString(to_sign.policy_value()); em::UserWhitelistProto* whitelist_proto = pol.mutable_user_whitelist(); ModifyWhitelist(email_, add_to_whitelist_, whitelist_proto); to_sign.set_policy_value(pol.SerializeAsString()); to_store_.set_policy_data(to_sign.SerializeAsString()); service_->StartSigningAttempt(to_store_.policy_data(), this); } void WhitelistOp::Fail(SignedSettings::ReturnCode code) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &WhitelistOp::PerformCallback, code, false)); } void WhitelistOp::Succeed(bool value) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &WhitelistOp::PerformCallback, SUCCESS, value)); } void WhitelistOp::OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& sig) { // Ensure we're on the UI thread, due to the need to send DBus traffic. if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &WhitelistOp::OnKeyOpComplete, return_code, sig)); return; } VLOG(2) << "WhitelistOp::OnKeyOpComplete return_code = " << return_code; // Now, sure we're on the UI thread. if (return_code == OwnerManager::SUCCESS) { to_store_.set_policy_data_signature( std::string(reinterpret_cast<const char*>(&sig[0]), sig.size())); store_op_ = CreateStorePolicyOp(&to_store_, this); // d_->OnSettingsOpCompleted() will be called by this call. store_op_->Execute(); } else { Fail(SignedSettings::MapKeyOpCode(return_code)); } } void WhitelistOp::OnSettingsOpCompleted(ReturnCode code, bool value) { if (value && to_store_.has_policy_data()) { em::PolicyData poldata; poldata.ParseFromString(to_store_.policy_data()); service_->set_cached_policy(poldata); Succeed(value); return; } Fail(NOT_FOUND); } void WhitelistOp::ModifyWhitelist(const std::string& email, bool add_to_whitelist, em::UserWhitelistProto* whitelist_proto) { int i = 0; const RepeatedPtrField<string>& whitelist = whitelist_proto->user_whitelist(); for (RepeatedPtrField<string>::const_iterator it = whitelist.begin(); it != whitelist.end(); ++it, ++i) { if (email == *it) break; } // |i| contains the index of |email|, if it is in |whitelist|. if (add_to_whitelist) { if (i >= whitelist.size()) // |email| was not in |whitelist|, we must add. whitelist_proto->add_user_whitelist(email); return; } else { if (i < whitelist.size()) { // |email| was in |whitelist|, we must remove. RepeatedPtrField<string>* change_list = whitelist_proto->mutable_user_whitelist(); change_list->SwapElements(i, whitelist.size() - 1); // Move to end. change_list->RemoveLast(); } return; } LOG(WARNING) << "Whitelist modification no-op: " << email; } void WhitelistOp::PerformCallback(SignedSettings::ReturnCode code, bool value) { d_->OnSettingsOpCompleted(code, value); } StorePropertyOp::StorePropertyOp(const std::string& name, const std::string& value, SignedSettings::Delegate<bool>* d) : name_(name), value_(value), d_(d), store_op_(NULL) { } StorePropertyOp::~StorePropertyOp() {} void StorePropertyOp::Execute() { if (service_->GetStatus(true) != OwnershipService::OWNERSHIP_TAKEN) { if (g_browser_process && g_browser_process->local_state() && SignedSettingsTempStorage::Store(name_, value_, g_browser_process->local_state())) { Succeed(true); return; } } if (!service_->has_cached_policy()) { TryToFetchPolicyAndCallBack(); return; } // Posts a task to the FILE thread to sign policy. em::PolicyData to_sign; to_sign.CheckTypeAndMergeFrom(service_->cached_policy()); SetInPolicy(name_, value_, &to_sign); to_store_.set_policy_data(to_sign.SerializeAsString()); service_->StartSigningAttempt(to_store_.policy_data(), this); } void StorePropertyOp::Fail(SignedSettings::ReturnCode code) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &StorePropertyOp::PerformCallback, code, false)); } void StorePropertyOp::Succeed(bool value) { BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &StorePropertyOp::PerformCallback, SUCCESS, value)); } void StorePropertyOp::OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& sig) { // Ensure we're on the UI thread, due to the need to send DBus traffic. if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &StorePropertyOp::OnKeyOpComplete, return_code, sig)); return; } VLOG(2) << "StorePropertyOp::OnKeyOpComplete return_code = " << return_code; // Now, sure we're on the UI thread. if (return_code == OwnerManager::SUCCESS) { to_store_.set_policy_data_signature( std::string(reinterpret_cast<const char*>(&sig[0]), sig.size())); store_op_ = CreateStorePolicyOp(&to_store_, this); // d_->OnSettingsOpCompleted() will be called by this call. store_op_->Execute(); } else { Fail(SignedSettings::MapKeyOpCode(return_code)); } } void StorePropertyOp::OnSettingsOpCompleted(ReturnCode code, bool value) { if (value && to_store_.has_policy_data()) { em::PolicyData poldata; poldata.ParseFromString(to_store_.policy_data()); service_->set_cached_policy(poldata); Succeed(value); return; } Fail(NOT_FOUND); } void StorePropertyOp::SetInPolicy(const std::string& prop, const std::string& value, em::PolicyData* poldata) { em::ChromeDeviceSettingsProto pol; pol.ParseFromString(poldata->policy_value()); if (prop == kAccountsPrefAllowNewUser) { em::AllowNewUsersProto* allow = pol.mutable_allow_new_users(); allow->set_allow_new_users(value == "true"); } else if (prop == kAccountsPrefAllowGuest) { em::GuestModeEnabledProto* guest = pol.mutable_guest_mode_enabled(); guest->set_guest_mode_enabled(value == "true"); } else if (prop == kAccountsPrefShowUserNamesOnSignIn) { em::ShowUserNamesOnSigninProto* show = pol.mutable_show_user_names(); show->set_show_user_names(value == "true"); } else if (prop == kSignedDataRoamingEnabled) { em::DataRoamingEnabledProto* roam = pol.mutable_data_roaming_enabled(); roam->set_data_roaming_enabled(value == "true"); } else if (prop == kSettingProxyEverywhere) { // TODO(cmasone): NOTIMPLEMENTED() once http://crosbug.com/13052 is fixed. bool success = pol.mutable_device_proxy_settings()->ParseFromString(value); DCHECK(success); } else { NOTREACHED(); } poldata->set_policy_value(pol.SerializeAsString()); } void StorePropertyOp::PerformCallback(SignedSettings::ReturnCode code, bool value) { d_->OnSettingsOpCompleted(code, value); } // static const char* RetrievePropertyOp::kVeritas[] = { "false", "true" }; RetrievePropertyOp::RetrievePropertyOp(const std::string& name, SignedSettings::Delegate<std::string>* d) : name_(name), d_(d) { } RetrievePropertyOp::~RetrievePropertyOp() {} void RetrievePropertyOp::Execute() { CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded()); // TODO(dilmah): Fix the race: // At the moment when device becomes owned there is lapse of time after // device has been owned and before temp_storage settings are finally // persisted into signed settings. // In this lapse of time Retrieve loses access to those settings. if (service_->GetStatus(true) != OwnershipService::OWNERSHIP_TAKEN) { if (g_browser_process && g_browser_process->local_state() && SignedSettingsTempStorage::Retrieve( name_, &value_, g_browser_process->local_state())) { Succeed(value_); return; } } if (!service_->has_cached_policy()) { TryToFetchPolicyAndCallBack(); return; } std::string value = LookUpInPolicy(name_); if (value.empty()) Fail(NOT_FOUND); else Succeed(value); } void RetrievePropertyOp::Fail(SignedSettings::ReturnCode code) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &RetrievePropertyOp::PerformCallback, code, std::string())); } void RetrievePropertyOp::Succeed(const std::string& value) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &RetrievePropertyOp::PerformCallback, SUCCESS, value)); } // DEPRECATED. void RetrievePropertyOp::OnKeyOpComplete( const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& sig) { NOTREACHED(); } std::string RetrievePropertyOp::LookUpInPolicy(const std::string& prop) { if (prop == kDeviceOwner) { const em::PolicyData& data = service_->cached_policy(); if (data.has_username() && !data.has_request_token()) return data.username(); return ""; } VLOG(2) << "Looking up " << prop; em::ChromeDeviceSettingsProto pol; pol.ParseFromString(service_->cached_policy().policy_value()); if (prop == kAccountsPrefAllowNewUser) { if (pol.has_allow_new_users() && pol.allow_new_users().has_allow_new_users() && pol.allow_new_users().allow_new_users()) { return kVeritas[1]; // New users allowed, user_whitelist() ignored. } // If we have the allow_new_users bool, and it is true, we honor that above. // In all other cases (don't have it, have it and it is set to false, etc), // We will honor the user_whitelist() if it is there and populated. // Otherwise, fail open (to do otherwise could render the device unusable). if (!pol.has_user_whitelist()) return kVeritas[1]; // Default to allowing new users. return kVeritas[pol.user_whitelist().user_whitelist_size() == 0]; } else if (prop == kAccountsPrefAllowGuest) { if (!pol.has_guest_mode_enabled() || !pol.guest_mode_enabled().has_guest_mode_enabled()) return kVeritas[1]; // Default to allowing guests; return kVeritas[pol.guest_mode_enabled().guest_mode_enabled()]; } else if (prop == kAccountsPrefShowUserNamesOnSignIn) { if (!pol.has_show_user_names() || !pol.show_user_names().has_show_user_names()) return kVeritas[1]; // Default to showing pods on the login screen; return kVeritas[pol.show_user_names().show_user_names()]; } else if (prop == kSignedDataRoamingEnabled) { if (!pol.has_data_roaming_enabled() || !pol.data_roaming_enabled().has_data_roaming_enabled()) return kVeritas[0]; // Default to disabling cellular data roaming; return kVeritas[pol.data_roaming_enabled().data_roaming_enabled()]; } else if (prop == kSettingProxyEverywhere) { // TODO(cmasone): NOTIMPLEMENTED() once http://crosbug.com/13052 is fixed. std::string serialized; if (!pol.has_device_proxy_settings() || !pol.device_proxy_settings().SerializeToString(&serialized)) return ""; // Default to invalid proxy config (will be ignored). return serialized; } return std::string(); } void RetrievePropertyOp::PerformCallback(SignedSettings::ReturnCode code, const std::string& value) { d_->OnSettingsOpCompleted(code, value); } StorePolicyOp::StorePolicyOp(em::PolicyFetchResponse* policy, SignedSettings::Delegate<bool>* d) : policy_(policy), d_(d) { } StorePolicyOp::~StorePolicyOp() {} // static void StorePolicyOp::OnBoolComplete(void* delegate, bool success) { StorePolicyOp* op = static_cast<StorePolicyOp*>(delegate); if (success) op->Succeed(true); else op->Fail(NOT_FOUND); } void StorePolicyOp::Execute() { // get protobuf contents to sign if (!policy_->has_policy_data()) Fail(OPERATION_FAILED); if (!policy_->has_policy_data_signature()) service_->StartSigningAttempt(policy_->policy_data(), this); else RequestStorePolicy(); } void StorePolicyOp::Fail(SignedSettings::ReturnCode code) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &StorePolicyOp::PerformCallback, code, false)); } void StorePolicyOp::Succeed(bool ignored) { SignedSettings::ReturnCode code = SUCCESS; bool to_ret = true; em::PolicyData poldata; if (SignedSettings::PolicyIsSane(*policy_, &poldata)) { service_->set_cached_policy(poldata); } else { code = NOT_FOUND; to_ret = false; } BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &StorePolicyOp::PerformCallback, code, to_ret)); } void StorePolicyOp::OnKeyOpComplete(const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload) { // Ensure we're on the UI thread, due to the need to send DBus traffic. if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &StorePolicyOp::OnKeyOpComplete, return_code, payload)); return; } VLOG(2) << "StorePolicyOp::OnKeyOpComplete return_code = " << return_code; // Now, sure we're on the UI thread. if (return_code == OwnerManager::SUCCESS) { policy_->set_policy_data_signature(std::string(payload.begin(), payload.end())); RequestStorePolicy(); return; } Fail(SignedSettings::MapKeyOpCode(return_code)); } void StorePolicyOp::RequestStorePolicy() { std::string serialized; if (policy_->SerializeToString(&serialized)) { CrosLibrary::Get()->GetLoginLibrary()->RequestStorePolicy( serialized, &StorePolicyOp::OnBoolComplete, this); } else { Fail(OPERATION_FAILED); } } void StorePolicyOp::PerformCallback(SignedSettings::ReturnCode code, bool value) { d_->OnSettingsOpCompleted(code, value); } RetrievePolicyOp::RetrievePolicyOp( SignedSettings::Delegate<const em::PolicyFetchResponse&>* d) : d_(d) { } RetrievePolicyOp::~RetrievePolicyOp() {} void RetrievePolicyOp::Execute() { CrosLibrary::Get()->GetLoginLibrary()->RequestRetrievePolicy( &RetrievePolicyOp::OnStringComplete, this); } void RetrievePolicyOp::Fail(SignedSettings::ReturnCode code) { VLOG(2) << "RetrievePolicyOp::Execute() failed with " << code; BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &RetrievePolicyOp::PerformCallback, code, em::PolicyFetchResponse())); } void RetrievePolicyOp::Succeed(const em::PolicyFetchResponse& value) { em::PolicyData poldata; if (SignedSettings::PolicyIsSane(value, &poldata)) { service_->set_cached_policy(poldata); BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &RetrievePolicyOp::PerformCallback, SUCCESS, value)); } else { Fail(NOT_FOUND); } } void RetrievePolicyOp::OnKeyOpComplete( const OwnerManager::KeyOpCode return_code, const std::vector<uint8>& payload) { if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &RetrievePolicyOp::OnKeyOpComplete, return_code, payload)); return; } // Now, sure we're on the UI thread. if (return_code == OwnerManager::SUCCESS) Succeed(policy_); else Fail(SignedSettings::MapKeyOpCode(return_code)); } // static void RetrievePolicyOp::OnStringComplete(void* delegate, const char* out, const unsigned int len) { RetrievePolicyOp* op = static_cast<RetrievePolicyOp*>(delegate); op->ProcessPolicy(out, len); } void RetrievePolicyOp::ProcessPolicy(const char* out, const unsigned int len) { if (!out || !policy_.ParseFromString(std::string(out, len)) || (!policy_.has_policy_data() && !policy_.has_policy_data_signature())) { Fail(NOT_FOUND); return; } if (!policy_.has_policy_data()) { Fail(OPERATION_FAILED); return; } if (!policy_.has_policy_data_signature()) { Fail(BAD_SIGNATURE); return; } std::vector<uint8> sig; const char* sig_ptr = policy_.policy_data_signature().c_str(); sig.assign(sig_ptr, sig_ptr + policy_.policy_data_signature().length()); service_->StartVerifyAttempt(policy_.policy_data(), sig, this); } void RetrievePolicyOp::PerformCallback(SignedSettings::ReturnCode code, const em::PolicyFetchResponse& value) { d_->OnSettingsOpCompleted(code, value); } } // namespace chromeos