blob: 627f0e19be551d61ba4de42d04daf33d9e9c016f [file] [log] [blame]
// Copyright 2016 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 "authpolicy/authpolicy.h"
#include <utility>
#include <vector>
#include <base/strings/stringprintf.h>
#include <bindings/chrome_device_policy.pb.h>
#include <bindings/device_management_backend.pb.h>
#include <brillo/dbus/dbus_method_invoker.h>
#include <chromeos/dbus/service_constants.h>
#include "authpolicy/errors.h"
#include "authpolicy/policy/preg_policy_encoder.h"
#include "authpolicy/policy/proto/cloud_policy.pb.h"
#include "authpolicy/samba_interface.h"
namespace em = enterprise_management;
using brillo::dbus_utils::ExtractMethodCallResults;
namespace authpolicy {
AuthPolicy::AuthPolicy(
brillo::dbus_utils::ExportedObjectManager* object_manager)
: org::chromium::AuthPolicyAdaptor(this),
dbus_object_(object_manager, object_manager->GetBus(),
org::chromium::AuthPolicyAdaptor::GetObjectPath()),
session_manager_proxy_(nullptr),
weak_ptr_factory_(this) {}
void AuthPolicy::RegisterAsync(
const AsyncEventSequencer::CompletionAction& completion_callback) {
RegisterWithDBusObject(&dbus_object_);
dbus_object_.RegisterAsync(completion_callback);
session_manager_proxy_ = dbus_object_.GetBus()->GetObjectProxy(
login_manager::kSessionManagerServiceName,
dbus::ObjectPath(login_manager::kSessionManagerServicePath));
DCHECK(session_manager_proxy_);
}
bool AuthPolicy::AuthenticateUser(brillo::ErrorPtr* error,
const std::string& in_user_principal_name,
const dbus::FileDescriptor& in_password_fd,
int32_t* out_error_code,
std::string* out_account_id) {
LOG(INFO) << "Received 'AuthenticateUser' request";
*out_error_code = 0;
// Call samba to authenticate user and get account id.
const char* error_code;
if (!samba_.AuthenticateUser(in_user_principal_name, in_password_fd.value(),
out_account_id, &error_code)) {
brillo::Error::AddToPrintf(error, FROM_HERE, errors::kDomain,
error_code, "Failed to authenticate user.");
return false;
}
LOG(INFO) << "AuthenticateUser succeeded";
return true;
}
bool AuthPolicy::JoinADDomain(brillo::ErrorPtr* error,
const std::string& in_machine_name,
const std::string& in_user_principal_name,
const dbus::FileDescriptor& in_password_fd,
int32_t* out_error_code) {
LOG(INFO) << "Received 'JoinADDomain' request";
*out_error_code = 0;
// Call samba to join machine to the AD domain.
const char* error_code;
if (!samba_.JoinMachine(in_machine_name, in_user_principal_name,
in_password_fd.value(), &error_code)) {
brillo::Error::AddToPrintf(error, FROM_HERE, errors::kDomain,
error_code, "Failed to join AD domain.");
return false;
}
LOG(INFO) << "JoinADDomain succeeded";
return true;
}
void AuthPolicy::RefreshUserPolicy(PolicyResponseCallback response,
const std::string& in_account_id) {
LOG(INFO) << "Received 'RefreshUserPolicy' request";
// Fetch GPOs for the current user.
const char* error_code;
std::vector<base::FilePath> gpo_file_paths;
if (!samba_.FetchUserGpos(in_account_id, &gpo_file_paths, &error_code)) {
response->ReplyWithError(FROM_HERE, errors::kDomain, error_code,
"Failed to fetch user policy.");
return;
}
// Load GPOs into policy.
em::CloudPolicySettings policy;
if (!policy::ParsePRegFilesIntoUserPolicy(gpo_file_paths, &policy,
&error_code)) {
response->ReplyWithError(FROM_HERE, errors::kDomain, error_code,
"Failed to parse user policy preg files.");
return;
}
LOG(INFO) << "User policy fetch and parsing succeeded";
// Send policy to Session Manager.
StoreUserPolicy(in_account_id, policy, std::move(response));
}
void AuthPolicy::RefreshDevicePolicy(PolicyResponseCallback response) {
LOG(INFO) << "Received 'RefreshDevicePolicy' request";
// Fetch GPOs for the device.
const char* error_code;
std::vector<base::FilePath> gpo_file_paths;
if (!samba_.FetchDeviceGpos(&gpo_file_paths, &error_code)) {
response->ReplyWithError(FROM_HERE, errors::kDomain, error_code,
"Failed to refresh device policy");
return;
}
// Load GPOs into policy.
em::ChromeDeviceSettingsProto policy;
if (!policy::ParsePRegFilesIntoDevicePolicy(gpo_file_paths, &policy,
&error_code)) {
response->ReplyWithError(FROM_HERE, errors::kDomain, error_code,
"Failed to parse device policy preg files.");
return;
}
LOG(INFO) << "Device policy fetch and parsing succeeded";
// Send policy to Session Manager.
StoreDevicePolicy(policy, std::move(response));
}
void AuthPolicy::StoreUserPolicy(const std::string& account_id,
const em::CloudPolicySettings& policy,
PolicyResponseCallback callback) {
em::PolicyFetchResponse policy_response;
// Note: No signature required here, AD policy is unsigned!
if (!policy.SerializeToString(policy_response.mutable_policy_data())) {
callback->ReplyWithError(FROM_HERE, errors::kDomain,
errors::kStorePolicyFailed,
"Failed to serialize user policy protobuf.");
return;
}
StorePolicy(policy_response.SerializeAsString(), &account_id,
std::move(callback));
}
void AuthPolicy::StoreDevicePolicy(const em::ChromeDeviceSettingsProto& policy,
PolicyResponseCallback callback) {
em::PolicyFetchResponse policy_response;
// Note: No signature required here, AD policy is unsigned!
if (!policy.SerializeToString(policy_response.mutable_policy_data())) {
callback->ReplyWithError(FROM_HERE, errors::kDomain,
errors::kStorePolicyFailed,
"Failed to serialize device policy protobuf.");
return;
}
StorePolicy(policy_response.SerializeAsString(), nullptr,
std::move(callback));
}
void AuthPolicy::StorePolicy(const std::string& policy_blob,
const std::string* account_id,
PolicyResponseCallback callback) {
const char* const method =
account_id ? login_manager::kSessionManagerStoreUnsignedPolicyForUser
: login_manager::kSessionManagerStoreUnsignedPolicy;
LOG(INFO) << "Calling Session Manager D-Bus method " << method;
dbus::MethodCall method_call(login_manager::kSessionManagerInterface, method);
dbus::MessageWriter writer(&method_call);
if (account_id) writer.AppendString(*account_id);
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(policy_blob.data()), policy_blob.size());
session_manager_proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&AuthPolicy::OnPolicyStored, weak_ptr_factory_.GetWeakPtr(),
method, base::Passed(&callback)));
}
void AuthPolicy::OnPolicyStored(const char* method,
PolicyResponseCallback callback,
dbus::Response* response) {
brillo::ErrorPtr error;
bool done = false;
std::string msg;
if (!response) {
msg = base::StringPrintf("Call to %s failed. No response.", method);
} else if (!ExtractMethodCallResults(response, &error, &done)) {
msg = base::StringPrintf("Call to %s failed. %s",
method, error ? error->GetMessage().c_str() : "Unknown error.");
} else if (!done) {
msg = base::StringPrintf("Call to %s failed. Call returned false.", method);
}
if (!msg.empty()) {
LOG(ERROR) << msg;
callback->ReplyWithError(FROM_HERE, errors::kDomain,
errors::kStorePolicyFailed, msg);
} else {
LOG(INFO) << "Call to " << method << " succeeded.";
callback->Return(0);
}
}
} // namespace authpolicy