blob: 5fdfbb0c7d604ad5c2290233f255fb4116ed6a2e [file] [log] [blame]
// Copyright (c) 2011 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 "device_policy_service.h"
#include <base/file_path.h>
#include <base/logging.h>
#include <base/message_loop_proxy.h>
#include <base/task.h>
#include "login_manager/bindings/chrome_device_policy.pb.h"
#include "login_manager/bindings/device_management_backend.pb.h"
#include "login_manager/key_generator.h"
#include "login_manager/nss_util.h"
#include "login_manager/owner_key.h"
#include "login_manager/owner_key_loss_mitigator.h"
#include "login_manager/policy_store.h"
namespace em = enterprise_management;
namespace login_manager {
using google::protobuf::RepeatedPtrField;
using std::string;
// static
const char DevicePolicyService::kPolicyPath[] = "/var/lib/whitelist/policy";
// static
const char DevicePolicyService::kDevicePolicyType[] = "google/chromeos/device";
DevicePolicyService::~DevicePolicyService() {
}
// static
DevicePolicyService* DevicePolicyService::Create(
OwnerKeyLossMitigator* mitigator,
const scoped_refptr<base::MessageLoopProxy>& main_loop,
const scoped_refptr<base::MessageLoopProxy>& io_loop) {
NssUtil* nss = NssUtil::Create();
return new DevicePolicyService(new PolicyStore(FilePath(kPolicyPath)),
new OwnerKey(nss->GetOwnerKeyFilePath()),
main_loop,
io_loop,
nss,
mitigator);
}
bool DevicePolicyService::CheckAndHandleOwnerLogin(
const std::string& current_user,
bool* is_owner,
Error* error) {
// If the current user is the owner, and isn't whitelisted or set as the owner
// in the settings blob, then do so.
bool can_access_key = CurrentUserHasOwnerKey(key()->public_key_der(), error);
if (can_access_key)
StoreOwnerProperties(current_user, NULL);
// Now, the flip side...if we believe the current user to be the owner based
// on the user field in policy, and she DOESN'T have the private half of the
// public key, we must mitigate.
*is_owner = CurrentUserIsOwner(current_user);
if (*is_owner && !can_access_key) {
if (!mitigator_->Mitigate(key()))
return false;
}
return true;
}
bool DevicePolicyService::ValidateAndStoreOwnerKey(
const std::string& current_user,
const std::string& buf) {
std::vector<uint8> pub_key;
NssUtil::BlobFromBuffer(buf, &pub_key);
Error error;
if (!CurrentUserHasOwnerKey(pub_key, &error))
return false;
// If we're not mitigating a key loss, we should be able to populate |key_|.
// If we're mitigating a key loss, we should be able to clobber |key_|.
if ((!mitigator_->Mitigating() && !key()->PopulateFromBuffer(pub_key)) ||
(mitigator_->Mitigating() && !key()->ClobberCompromisedKey(pub_key))) {
return false;
}
PersistKey();
if (StoreOwnerProperties(current_user, &error)) {
PersistPolicy();
} else {
LOG(WARNING) << "Could not immediately store owner properties in policy";
}
return true;
}
DevicePolicyService::DevicePolicyService(
PolicyStore* policy_store,
OwnerKey* policy_key,
const scoped_refptr<base::MessageLoopProxy>& main_loop,
const scoped_refptr<base::MessageLoopProxy>& io_loop,
NssUtil* nss,
OwnerKeyLossMitigator* mitigator)
: PolicyService(policy_store, policy_key, main_loop, io_loop),
nss_(nss),
mitigator_(mitigator) {
}
bool DevicePolicyService::KeyMissing() {
return key()->HaveCheckedDisk() && !key()->IsPopulated();
}
bool DevicePolicyService::StoreOwnerProperties(const std::string& current_user,
Error* error) {
const em::PolicyFetchResponse& policy(store()->Get());
em::PolicyData poldata;
if (policy.has_policy_data())
poldata.ParseFromString(policy.policy_data());
em::ChromeDeviceSettingsProto polval;
if (poldata.has_policy_type() &&
poldata.policy_type() == kDevicePolicyType) {
if (poldata.has_policy_value())
polval.ParseFromString(poldata.policy_value());
} else {
poldata.set_policy_type(kDevicePolicyType);
}
// If there existed some device policy, we've got it now!
// Update the UserWhitelistProto inside the ChromeDeviceSettingsProto we made.
em::UserWhitelistProto* whitelist_proto = polval.mutable_user_whitelist();
bool on_list = false;
const RepeatedPtrField<string>& whitelist = whitelist_proto->user_whitelist();
for (RepeatedPtrField<string>::const_iterator it = whitelist.begin();
it != whitelist.end();
++it) {
if (on_list = (current_user == *it))
break;
}
if (poldata.has_username() && poldata.username() == current_user &&
on_list &&
key()->Equals(policy.new_public_key())) {
return true; // No changes are needed.
}
if (!on_list) {
// Add owner to the whitelist and turn off whitelist enforcement if it is
// currently not explicitly turned on or off.
whitelist_proto->add_user_whitelist(current_user);
if (!polval.has_allow_new_users())
polval.mutable_allow_new_users()->set_allow_new_users(true);
}
poldata.set_username(current_user);
// We have now updated the whitelist and owner setting in |polval|.
// We need to put it into |poldata|, serialize that, sign it, and
// write it back.
poldata.set_policy_value(polval.SerializeAsString());
std::string new_data = poldata.SerializeAsString();
std::vector<uint8> sig;
const uint8* data = reinterpret_cast<const uint8*>(new_data.c_str());
if (!key() || !key()->Sign(data, new_data.length(), &sig)) {
const char err_msg[] = "Could not sign policy containing new owner data.";
LOG_IF(ERROR, error) << err_msg;
LOG_IF(WARNING, !error) << err_msg;
error->Set(CHROMEOS_LOGIN_ERROR_ILLEGAL_PUBKEY, err_msg);
return false;
}
em::PolicyFetchResponse new_policy;
new_policy.CheckTypeAndMergeFrom(policy);
new_policy.set_policy_data(new_data);
new_policy.set_policy_data_signature(
std::string(reinterpret_cast<const char*>(&sig[0]), sig.size()));
const std::vector<uint8>& key_der = key()->public_key_der();
new_policy.set_new_public_key(
std::string(reinterpret_cast<const char*>(&key_der[0]), key_der.size()));
store()->Set(new_policy);
return true;
}
bool DevicePolicyService::CurrentUserHasOwnerKey(const std::vector<uint8>& key,
Error* error) {
if (!nss_->MightHaveKeys())
return false;
if (!nss_->OpenUserDB()) {
const char msg[] = "Could not open the current user's NSS database.";
LOG(ERROR) << msg;
error->Set(CHROMEOS_LOGIN_ERROR_NO_USER_NSSDB, msg);
return false;
}
if (!nss_->GetPrivateKey(key)) {
const char msg[] = "Could not verify that public key belongs to the owner.";
LOG(WARNING) << msg;
error->Set(CHROMEOS_LOGIN_ERROR_ILLEGAL_PUBKEY, msg);
return false;
}
return true;
}
bool DevicePolicyService::CurrentUserIsOwner(const std::string& current_user) {
const em::PolicyFetchResponse& policy(store()->Get());
em::PolicyData poldata;
if (!policy.has_policy_data())
return false;
if (poldata.ParseFromString(policy.policy_data())) {
return (!poldata.has_request_token() &&
poldata.has_username() &&
poldata.username() == current_user);
}
return false;
}
} // namespace login_manager