blob: 2e38e3bef08a9a159b532a036886132b356f5ca8 [file] [log] [blame]
// Copyright 2017 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 "smbprovider/smbprovider.h"
#include <algorithm>
#include <map>
#include <utility>
#include <base/check.h>
#include <base/check_op.h>
#include <base/files/file.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/memory/ptr_util.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/stringprintf.h>
#include <crypto/sha2.h>
#include <dbus/smbprovider/dbus-constants.h>
#include "smbprovider/constants.h"
#include "smbprovider/file_copy_progress.h"
#include "smbprovider/iterator/caching_iterator.h"
#include "smbprovider/iterator/directory_iterator.h"
#include "smbprovider/iterator/post_depth_first_iterator.h"
#include "smbprovider/mount_manager.h"
#include "smbprovider/netbios_packet_parser.h"
#include "smbprovider/proto.h"
#include "smbprovider/proto_bindings/directory_entry.pb.h"
#include "smbprovider/recursive_copy_progress.h"
#include "smbprovider/samba_interface.h"
#include "smbprovider/smbprovider_helper.h"
namespace smbprovider {
bool GetShareEntries(const GetSharesOptionsProto& options,
ShareIterator iterator,
int32_t* error_code,
ProtoBlob* out_entries) {
DCHECK(error_code);
DCHECK(out_entries);
DirectoryEntryListProto directory_entries;
int32_t result = iterator.Init();
while (result == 0) {
if (iterator.IsDone()) {
*error_code = static_cast<int32_t>(
SerializeProtoToBlob(directory_entries, out_entries));
return true;
}
AddDirectoryEntry(iterator.Get(), &directory_entries);
result = iterator.Next();
}
// The while-loop is only exited if there is an error. A full successful
// execution will return from inside the above while-loop.
*error_code = GetErrorFromErrno(result);
LogOperationError(GetMethodName(options), GetMountId(options),
static_cast<ErrorType>(*error_code));
return false;
}
SmbProvider::SmbProvider(
std::unique_ptr<brillo::dbus_utils::DBusObject> dbus_object,
std::unique_ptr<MountManager> mount_manager,
std::unique_ptr<KerberosArtifactSynchronizer>
kerberos_artifact_synchronizer,
const base::FilePath& daemon_store_directory)
: org::chromium::SmbProviderAdaptor(this),
dbus_object_(std::move(dbus_object)),
mount_manager_(std::move(mount_manager)),
kerberos_artifact_synchronizer_(
std::move(kerberos_artifact_synchronizer)) {}
void SmbProvider::RegisterAsync(
const AsyncEventSequencer::CompletionAction& completion_callback) {
RegisterWithDBusObject(dbus_object_.get());
dbus_object_->RegisterAsync(completion_callback);
}
void SmbProvider::ReadShareEntries(const ProtoBlob& options_blob,
int32_t* error_code,
ProtoBlob* out_entries) {
DCHECK(error_code);
DCHECK(out_entries);
out_entries->clear();
std::string full_path;
GetSharesOptionsProto options;
if (ParseOptionsAndPath(options_blob, &options, &full_path, error_code)) {
SambaInterface* samba_interface = GetSambaInterface(GetMountId(options));
GetShareEntries(options, ShareIterator(full_path, samba_interface),
error_code, out_entries);
}
}
void SmbProvider::GetShares(const ProtoBlob& options_blob,
int32_t* error_code,
ProtoBlob* shares) {
DCHECK(error_code);
DCHECK(shares);
ReadShareEntries(options_blob, error_code, shares);
}
void SmbProvider::SetupKerberos(SetupKerberosCallback callback,
const std::string& account_identifier) {
kerberos_artifact_synchronizer_->SetupKerberos(
account_identifier,
base::BindOnce(&SmbProvider::HandleSetupKerberosResponse,
base::Unretained(this), std::move(callback)));
}
void SmbProvider::HandleSetupKerberosResponse(SetupKerberosCallback callback,
bool result) {
callback->Return(result);
}
ProtoBlob SmbProvider::ParseNetBiosPacket(const std::vector<uint8_t>& packet,
uint16_t transaction_id) {
const std::vector<std::string> servers =
netbios::ParsePacket(packet, transaction_id);
const HostnamesProto hostnames_proto = BuildHostnamesProto(servers);
std::vector<uint8_t> out_blob;
if (SerializeProtoToBlob(hostnames_proto, &out_blob) != ERROR_OK) {
return ProtoBlob();
}
return out_blob;
}
HostnamesProto SmbProvider::BuildHostnamesProto(
const std::vector<std::string>& hostnames) const {
HostnamesProto hostnames_proto;
for (const auto& hostname : hostnames) {
AddToHostnamesProto(hostname, &hostnames_proto);
}
return hostnames_proto;
}
SambaInterface* SmbProvider::GetSambaInterface(int32_t mount_id) const {
SambaInterface* samba_interface;
if (mount_id == kInternalMountId) {
samba_interface = mount_manager_->GetSystemSambaInterface();
} else {
bool success =
mount_manager_->GetSambaInterface(mount_id, &samba_interface);
DCHECK(success);
}
DCHECK(samba_interface);
return samba_interface;
}
template <typename Proto>
bool SmbProvider::GetFullPath(const Proto* options,
std::string* full_path) const {
DCHECK(options);
DCHECK(full_path);
const int32_t mount_id = GetMountId(*options);
const std::string entry_path = GetEntryPath(*options);
bool success = mount_manager_->GetFullPath(mount_id, entry_path, full_path);
if (!success) {
LOG(ERROR) << GetMethodName(*options) << " requested unknown mount_id "
<< mount_id;
}
return success;
}
template <>
bool SmbProvider::GetFullPath(const GetSharesOptionsProto* options,
std::string* full_path) const {
DCHECK(options);
DCHECK(full_path);
*full_path = GetEntryPath(*options);
return true;
}
template <typename Proto>
bool SmbProvider::ParseOptionsAndPath(const ProtoBlob& blob,
Proto* options,
std::string* full_path,
int32_t* error_code) {
if (!ParseOptionsProto(blob, options, error_code)) {
return false;
}
if (!GetFullPath(options, full_path)) {
*error_code = static_cast<int32_t>(ERROR_NOT_FOUND);
return false;
}
return true;
}
} // namespace smbprovider