blob: efcc2aadcb65e21815d82389c2f6286f35b90b86 [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.
#ifndef SMBPROVIDER_SMBPROVIDER_H_
#define SMBPROVIDER_SMBPROVIDER_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <base/memory/weak_ptr.h>
#include <dbus_adaptors/org.chromium.SmbProvider.h>
#include "smbprovider/copy_progress_interface.h"
#include "smbprovider/kerberos_artifact_synchronizer.h"
#include "smbprovider/proto.h"
#include "smbprovider/proto_bindings/directory_entry.pb.h"
#include "smbprovider/smbprovider_helper.h"
#include "smbprovider/temp_file_manager.h"
using brillo::dbus_utils::AsyncEventSequencer;
namespace smbprovider {
class DirectoryEntryListProto;
class MountManager;
class PostDepthFirstIterator;
class SambaInterface;
// Helper method that reads entries using an |iterator| and outputs them to
// |out_entries|. Returns true on success and sets |error_code| on failure.
// |options| is used for logging purposes.
template <typename Proto, typename Iterator>
bool GetEntries(const Proto& options,
Iterator iterator,
int32_t* error_code,
ProtoBlob* out_entries);
// Implementation of smbprovider's DBus interface. Mostly routes stuff between
// DBus and samba_interface.
class SmbProvider : public org::chromium::SmbProviderAdaptor,
public org::chromium::SmbProviderInterface {
public:
using SetupKerberosCallback =
std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<bool>>;
SmbProvider(
std::unique_ptr<brillo::dbus_utils::DBusObject> dbus_object,
std::unique_ptr<SambaInterface> samba_interface,
std::unique_ptr<MountManager> mount_manager,
std::unique_ptr<KerberosArtifactSynchronizer> kerberos_synchronizer,
bool enable_metadata_cache);
// org::chromium::SmbProviderInterface: (see org.chromium.SmbProvider.xml).
void Mount(const ProtoBlob& options_blob,
const base::ScopedFD& password_fd,
int32_t* error_code,
int32_t* mount_id) override;
int32_t Remount(const ProtoBlob& options_blob,
const base::ScopedFD& password_fd) override;
int32_t Unmount(const ProtoBlob& options_blob) override;
void ReadDirectory(const ProtoBlob& options_blob,
int32_t* error_code,
ProtoBlob* out_entries) override;
void GetMetadataEntry(const ProtoBlob& options_blob,
int32_t* error_code,
ProtoBlob* out_entry) override;
void OpenFile(const ProtoBlob& options_blob,
int32_t* error_code,
int32_t* file_id) override;
int32_t CloseFile(const ProtoBlob& options_blob) override;
int32_t DeleteEntry(const ProtoBlob& options_blob) override;
void ReadFile(const ProtoBlob& options_blob,
int32_t* error_code,
brillo::dbus_utils::FileDescriptor* temp_fd) override;
int32_t CreateFile(const ProtoBlob& options_blob) override;
int32_t Truncate(const ProtoBlob& options_blob) override;
int32_t WriteFile(const ProtoBlob& options_blob,
const base::ScopedFD& temp_fd) override;
int32_t CreateDirectory(const ProtoBlob& options_blob) override;
int32_t MoveEntry(const ProtoBlob& options_blob) override;
int32_t CopyEntry(const ProtoBlob& options_blob) override;
void GetDeleteList(const ProtoBlob& options,
int32_t* error_code,
brillo::dbus_utils::FileDescriptor* temp_fd,
int32_t* bytes_written) override;
void GetShares(const ProtoBlob& options_blob,
int32_t* error_code,
ProtoBlob* shares) override;
void SetupKerberos(SetupKerberosCallback callback,
const std::string& account_id) override;
ProtoBlob ParseNetBiosPacket(const std::vector<uint8_t>& packet,
uint16_t transaction_id) override;
void StartCopy(const ProtoBlob& options_blob,
int32_t* error_code,
int32_t* copy_token) override;
int32_t ContinueCopy(int32_t mount_id, int32_t copy_token) override;
// Register DBus object and interfaces.
void RegisterAsync(
const AsyncEventSequencer::CompletionAction& completion_callback);
private:
// Uses |options| to create the full path based on the mount id and entry path
// supplied in |options|. |full_path| will be unmodified on failure.
template <typename Proto>
bool GetFullPath(const Proto* options, std::string* full_path) const;
// Uses |options| to create the source and target paths based on the mount id,
// source path and target path supplied in |options|. |source_full_path| and
// |target_full_path| will be unmodified on failure.
template <typename Proto>
bool GetFullPaths(const Proto* options,
std::string* source_full_path,
std::string* target_full_path) const;
// Parses the raw contents of |blob| into |options| and validates that
// the required fields are all correctly set.
// |full_path| will contain the full path, including the mount root, based
// on the mount id and entry path supplied in |options|.
// On failure |error_code| will be populated and |options| and |full_path|
// are undefined.
template <typename Proto>
bool ParseOptionsAndPath(const ProtoBlob& blob,
Proto* options,
std::string* full_path,
int32_t* error_code);
// Variation of ParseOptionsAndPath. |source_path| and |target_path| will
// contain full paths, including the mount root, based on the mount id and
// paths supplied in |options|.
template <typename Proto>
bool ParseOptionsAndPaths(const ProtoBlob& blob,
Proto* options,
std::string* source_path,
std::string* target_path,
int32_t* error_code);
// Tests whether |mount_root| is a valid path to be mounted by attemping
// to open the directory.
bool CanAccessMount(const std::string& mount_root, int32_t* error_code);
// Helper method to get the type of an entry. Returns boolean indicating
// success. Sets is_directory to true for directory, and false for file.
// Fails when called on non-file, non-directory.
// On failure, returns false and sets |error_code|.
bool GetEntryType(const std::string& full_path,
int32_t* error_code,
bool* is_directory);
// Helper method to close the directory with id |dir_id|. Logs an error if the
// directory fails to close.
void CloseDirectory(int32_t dir_id);
// Removes |mount_id| from the |mount_manager_| object and sets |error_code|
// on failure.
bool RemoveMount(int32_t mount_id, int32_t* error_code);
// Adds mount |mount_root| to mount_manager_ and sets |error_code| on failure.
// Credentials such as |workgroup|, |username| and |password_fd| will be used
// if provided. Sets |mount_id| when mount is successful.
bool AddMount(const std::string& mount_root,
const std::string& workgroup,
const std::string& username,
const base::ScopedFD& password_fd,
int32_t* error_code,
int32_t* mount_id);
// Remounts |mount_root| on mount_manager_ with |mount_id| and sets
// |error_code| on failure.
bool Remount(const std::string& mount_root,
int32_t mount_id,
const std::string& workgroup,
const std::string& username,
const base::ScopedFD& password_fd,
int32_t* error_code);
// Removes |mount_id| from mount_manager_ if |mount_id| is mounted.
void RemoveMountIfMounted(int32_t mount_id);
// Helper method to read a file with valid |options| and output the results
// into a |buffer|. This sets |error_code| on failure.
bool ReadFileIntoBuffer(const ReadFileOptionsProto& options,
int32_t* error_code,
std::vector<uint8_t>* buffer);
// Helper method to write data from a |buffer| into a temporary file and
// outputs the resulting file descriptor into |temp_fd|. |options| is used for
// logging purposes. This sets |error_code| on failure.
template <typename Proto>
bool WriteTempFile(const Proto& options,
const std::vector<uint8_t>& buffer,
int32_t* error_code,
brillo::dbus_utils::FileDescriptor* temp_fd);
// Writes |delete_list| to a temporary file and outputs the resulting file
// descriptor into |temp_fd|. Sets |bytes_written| to the number of bytes
// if writing suceeds, -1 on failure. |options| is used for logging. Sets
// |error_code| on failure.
bool WriteDeleteListToTempFile(const GetDeleteListOptionsProto& options,
const DeleteListProto& delete_list,
int32_t* error_code,
brillo::dbus_utils::FileDescriptor* temp_fd,
int32_t* bytes_written);
// Helper method to write data from a |buffer| into a file specified by
// |file_id|. |options| is used for logging. Returns true on success, and sets
// |error_code| on failure.
template <typename Proto>
bool WriteFileFromBuffer(const Proto& options,
int32_t file_id,
const std::vector<uint8_t>& buffer,
int32_t* error_code);
// Moves an entry at |source_path| to |target_path|. |options| is used for
// logging. Returns true on success. Sets |error| and returns false on
// failure.
bool MoveEntry(const MoveEntryOptionsProto& options,
const std::string& source_path,
const std::string& target_path,
int32_t* error);
// Calls delete on the contents of |dir_path| via postorder traversal.
// RecursiveDelete exits and returns error if an entry cannot be deleted
// or there was a Samba error iterating over entries.
int32_t RecursiveDelete(const std::string& dir_path);
// Calls delete on a DirectoryEntry. Returns the result from either DeleteFile
// or DeleteDirectory.
int32_t DeleteDirectoryEntry(const DirectoryEntry& entry);
// Calls Unlink.
int32_t DeleteFile(const std::string& file_path);
// Calls RemoveDirectory.
int32_t DeleteDirectory(const std::string& dir_path);
// Helper method to construct a PostDepthFirstIterator for a given
// |full_path|.
PostDepthFirstIterator GetPostOrderIterator(const std::string& full_path);
// Opens a file located at |full_path| with permissions based on the protobuf.
// |file_id| is the file handle for the opened file, and error will be set on
// failure. |options| is used for permissions and logging.
// GetOpenFilePermissions must be overloaded to new protobufs using this
// method. Returns true on success.
template <typename Proto>
bool OpenFile(const Proto& options,
const std::string& full_path,
int32_t* error,
int32_t* file_id);
// Closes a file with handle |file_id|. |options| is used for logging
// purposes. |error| is set on failure. Returns true on success.
template <typename Proto>
bool CloseFile(const Proto& options, int32_t file_id, int32_t* error);
// Truncates a file with handle |file_id| to the desired |length| and closes
// the file whether or not the truncate was successful. |options| is used for
// logging purposes. |error| is set on failure. Returns true on success.
template <typename Proto>
bool TruncateAndCloseFile(const Proto& options,
int32_t file_id,
int64_t length,
int32_t* error);
// Helper method to seek given a proto |options|.
// On failure |error_code| will be populated.
template <typename Proto>
bool Seek(const Proto& options, int32_t* error_code);
// Creates the parent directories based on |options| if necessary. This call
// will return true if no directories need to be created. Returns true on
// success and sets |error_code| on failure.
bool CreateParentsIfNecessary(const CreateDirectoryOptionsProto& options,
int32_t* error_code);
// Helper method to create nested directories in |paths|. |paths| must be a
// successive hierarchy of directories starting from the top-most parent. This
// will succeed even if all the directories in |paths| already exists.
// |options| is used for logging purposes. Returns true on success and sets
// |error_code| on failure.
bool CreateNestedDirectories(const CreateDirectoryOptionsProto& options,
const std::vector<std::string>& paths,
int32_t* error_code);
// Helper method to create a single directory at |full_path|. |options| is
// used for logging purposes. If |ignore_existing| is true, this will ignore
// EEXIST errors. Returns true on success and sets |error_code| on failure.
template <typename Proto>
bool CreateSingleDirectory(const Proto& options,
const std::string& full_path,
bool ignore_existing,
int32_t* error_code);
// Generates a vector of |parent_paths| from a directory path in |options|.
// The path must be prefixed with "/". |parent_paths| will include the mount
// root and will exclude the path in |options|. Passing in "/1/2/3" will
// generate ["smb://{mount}/1", "smb://{mount}/1/2"]. If the path has no
// parents aside from "/", no paths will be generated. Returns true on success
// and sets |error_code| on failure.
bool GenerateParentPaths(const CreateDirectoryOptionsProto& options,
int32_t* error_code,
std::vector<std::string>* parent_paths);
// Creates a file at |full_path|. Sets |file_id| to fd of newly created file.
// Returns false and sets |error| on failure. |options| is used for
template <typename Proto>
bool CreateFile(const Proto& options,
const std::string& full_path,
int32_t* file_id,
int32_t* error);
// Copies the entry at |source_path| to |target_path|. Returns true on
// success. Returns false and sets |error_code| on failure.
bool CopyEntry(const CopyEntryOptionsProto& options,
const std::string& source_path,
const std::string& target_path,
int32_t* error_code);
// Copies the file at |source_path| to a created file at |target_path|.
// Returns true on success. Returns false and sets |error_code| on failure.
bool CopyFile(const CopyEntryOptionsProto& options,
const std::string& source_path,
const std::string& target_path,
int32_t* error_code);
// Helper method that fills |buffer| by reading the file with handle
// |file_id|. Returns true and sets |bytes_read| on success. Returns false and
// sets |error_code| on failure. |options| is used for logging.
template <typename Proto>
bool ReadToBuffer(const Proto& options,
int32_t file_id,
std::vector<uint8_t>* buffer,
size_t* bytes_read,
int32_t* error_code);
// Reads the entries in a directory using the specified type of |Iterator| and
// outputs the entries in |out_entries|. |options_blob| is parsed into a
// |Proto| object and is used as input for the iterator. |error_code| is set
// on failure.
template <typename Proto, typename Iterator>
void ReadDirectoryEntries(const ProtoBlob& options_blob,
bool include_metadata,
int32_t* error_code,
ProtoBlob* out_entries);
// Populates |delete_list| with an ordered list of relative paths of entries
// that must be deleted in order to recursively delete |full_path|.
int32_t GenerateDeleteList(const GetDeleteListOptionsProto& options,
const std::string& full_path,
bool is_directory,
DeleteListProto* delete_list);
// Generates an empty file with a file descriptor for transport over D-Bus.
// This is needed since FileDescriptor causes a crash while being transported
// if it is not valid.
brillo::dbus_utils::FileDescriptor GenerateEmptyFile();
// Returns the relative path to |entry_path| by removing the server path
// associated with |mount_id|.
std::string GetRelativePath(int32_t mount_id, const std::string& entry_path);
// Callback handler for SetupKerberos.
void HandleSetupKerberosResponse(SetupKerberosCallback callback, bool result);
// Creates a HostnamesProto from a list of |hostnames|.
HostnamesProto BuildHostnamesProto(
const std::vector<std::string>& hostnames) const;
// Starts a copy of |source_path| to |target_path|.
// Returns ERROR_COPY_PENDING and sets |copy_token| if the copy must be
// continued, ERROR_OK if the copy was completed successfully, and any other
// ErrorType if an error is encountered.
ErrorType StartCopy(const CopyEntryOptionsProto& options,
const std::string& source_path,
const std::string& target_path,
int32_t* copy_token);
// Starts a recursive copy of the directory at |source_path| to |target_path|.
// Returns ERROR_COPY_PENDING and sets |copy_token| if the copy must be
// continued, ERROR_OK if the copy was completed successfully, and any other
// ErrorType if an error is encountered.
ErrorType StartDirectoryCopy(const CopyEntryOptionsProto& options,
const std::string& source_path,
const std::string& target_path,
int32_t* copy_token);
// Starts a copy of the file at |source_path| to |target_path|.
// Returns ERROR_COPY_PENDING and sets |copy_token| if the copy must be
// continued, ERROR_OK if the copy was completed successfully, and any other
// ErrorType if an error is encountered.
ErrorType StartFileCopy(const CopyEntryOptionsProto& options,
const std::string& source_path,
const std::string& target_path,
int32_t* copy_token);
template <typename CopyProgressType>
ErrorType StartCopyProgress(const CopyEntryOptionsProto& options,
const std::string& source_path,
const std::string& target_path,
int32_t* copy_token);
// Continues the copy mapped to |copy_token|. Returns ERROR_COPY_PENDING
// if the copy must be continued, ERROR_OK if the copy was completed
// successfully, and any other ErrorType if an error is encountered.
ErrorType ContinueCopy(int32_t copy_token);
std::unique_ptr<SambaInterface> samba_interface_;
std::unique_ptr<brillo::dbus_utils::DBusObject> dbus_object_;
std::unique_ptr<MountManager> mount_manager_;
std::unique_ptr<KerberosArtifactSynchronizer> kerberos_synchronizer_;
TempFileManager temp_file_manager_;
// Keeps track of in-progress copy operations. Maps a copy token to a
// CopyProgress.
int32_t copy_counter_ = 0;
std::map<int32_t, std::unique_ptr<CopyProgressInterface>> copy_tracker_;
bool metadata_cache_enabled_;
DISALLOW_COPY_AND_ASSIGN(SmbProvider);
};
} // namespace smbprovider
#endif // SMBPROVIDER_SMBPROVIDER_H_