| // Copyright (c) 2012 The Chromium OS 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 "login_manager/policy_service.h" |
| |
| #include <stdint.h> |
| |
| #include <string> |
| #include <utility> |
| |
| #include <base/bind.h> |
| #include <base/callback.h> |
| #include <base/location.h> |
| #include <base/logging.h> |
| #include <base/synchronization/waitable_event.h> |
| #include <brillo/message_loops/message_loop.h> |
| #include <chromeos/dbus/service_constants.h> |
| |
| #include "bindings/device_management_backend.pb.h" |
| #include "login_manager/blob_util.h" |
| #include "login_manager/dbus_util.h" |
| #include "login_manager/nss_util.h" |
| #include "login_manager/policy_key.h" |
| #include "login_manager/policy_store.h" |
| #include "login_manager/system_utils.h" |
| |
| namespace em = enterprise_management; |
| |
| namespace login_manager { |
| |
| PolicyService::PolicyService(std::unique_ptr<PolicyStore> policy_store, |
| PolicyKey* policy_key) |
| : policy_store_(std::move(policy_store)), |
| policy_key_(policy_key), |
| delegate_(NULL), |
| weak_ptr_factory_(this) {} |
| |
| PolicyService::~PolicyService() = default; |
| |
| bool PolicyService::Store(const std::vector<uint8_t>& policy_blob, |
| int key_flags, |
| SignatureCheck signature_check, |
| const Completion& completion) { |
| em::PolicyFetchResponse policy; |
| if (!policy.ParseFromArray(policy_blob.data(), policy_blob.size()) || |
| !policy.has_policy_data()) { |
| constexpr char kMessage[] = "Unable to parse policy protobuf."; |
| LOG(ERROR) << kMessage; |
| completion.Run(CreateError(dbus_error::kSigDecodeFail, kMessage)); |
| return false; |
| } |
| |
| return StorePolicy(policy, key_flags, signature_check, completion); |
| } |
| |
| bool PolicyService::Retrieve(std::vector<uint8_t>* policy_blob) { |
| *policy_blob = SerializeAsBlob(store()->Get()); |
| return true; |
| } |
| |
| void PolicyService::PersistPolicy(const Completion& completion) { |
| const bool success = store()->Persist(); |
| OnPolicyPersisted(completion, |
| success ? dbus_error::kNone : dbus_error::kSigEncodeFail); |
| } |
| |
| void PolicyService::PostPersistKeyTask() { |
| brillo::MessageLoop::current()->PostTask( |
| FROM_HERE, |
| base::Bind(&PolicyService::PersistKey, weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void PolicyService::PostPersistPolicyTask(const Completion& completion) { |
| brillo::MessageLoop::current()->PostTask( |
| FROM_HERE, base::Bind(&PolicyService::PersistPolicy, |
| weak_ptr_factory_.GetWeakPtr(), completion)); |
| } |
| |
| bool PolicyService::StorePolicy(const em::PolicyFetchResponse& policy, |
| int key_flags, |
| SignatureCheck signature_check, |
| const Completion& completion) { |
| if (signature_check == SignatureCheck::kDisabled) { |
| store()->Set(policy); |
| PostPersistPolicyTask(completion); |
| return true; |
| } |
| |
| // Determine if the policy has pushed a new owner key and, if so, set it. |
| if (policy.has_new_public_key() && !key()->Equals(policy.new_public_key())) { |
| // The policy contains a new key, and it is different from |key_|. |
| std::vector<uint8_t> der = StringToBlob(policy.new_public_key()); |
| |
| bool installed = false; |
| if (key()->IsPopulated()) { |
| if (policy.has_new_public_key_signature() && (key_flags & KEY_ROTATE)) { |
| // Graceful key rotation. |
| LOG(INFO) << "Attempting policy key rotation."; |
| installed = |
| key()->Rotate(der, StringToBlob(policy.new_public_key_signature())); |
| } |
| } else if (key_flags & KEY_INSTALL_NEW) { |
| LOG(INFO) << "Attempting to install new policy key."; |
| installed = key()->PopulateFromBuffer(der); |
| } |
| if (!installed && (key_flags & KEY_CLOBBER)) { |
| LOG(INFO) << "Clobbering existing policy key."; |
| installed = key()->ClobberCompromisedKey(der); |
| } |
| |
| if (!installed) { |
| constexpr char kMessage[] = "Failed to install policy key!"; |
| LOG(ERROR) << kMessage; |
| completion.Run(CreateError(dbus_error::kPubkeySetIllegal, kMessage)); |
| return false; |
| } |
| |
| // If here, need to persist the key just loaded into memory to disk. |
| PostPersistKeyTask(); |
| } |
| |
| // Validate signature on policy and persist to disk. |
| if (!key()->Verify(StringToBlob(policy.policy_data()), |
| StringToBlob(policy.policy_data_signature()))) { |
| constexpr char kMessage[] = "Signature could not be verified."; |
| LOG(ERROR) << kMessage; |
| completion.Run(CreateError(dbus_error::kVerifyFail, kMessage)); |
| return false; |
| } |
| |
| store()->Set(policy); |
| PostPersistPolicyTask(completion); |
| return true; |
| } |
| |
| void PolicyService::OnKeyPersisted(bool status) { |
| if (status) |
| LOG(INFO) << "Persisted policy key to disk."; |
| else |
| LOG(ERROR) << "Failed to persist policy key to disk."; |
| if (delegate_) |
| delegate_->OnKeyPersisted(status); |
| } |
| |
| void PolicyService::OnPolicyPersisted(const Completion& completion, |
| const std::string& dbus_error_code) { |
| brillo::ErrorPtr error; |
| if (dbus_error_code != dbus_error::kNone) { |
| constexpr char kMessage[] = "Failed to persist policy to disk."; |
| LOG(ERROR) << kMessage << ": " << dbus_error_code; |
| error = CreateError(dbus_error_code, kMessage); |
| } |
| |
| if (!completion.is_null()) |
| completion.Run(std::move(error)); |
| else |
| error.reset(); |
| |
| if (delegate_) |
| delegate_->OnPolicyPersisted(dbus_error_code == dbus_error::kNone); |
| } |
| |
| void PolicyService::PersistKey() { |
| OnKeyPersisted(key()->Persist()); |
| } |
| |
| } // namespace login_manager |