// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_ASH_SMB_CLIENT_SMB_SERVICE_H_
#define CHROME_BROWSER_ASH_SMB_CLIENT_SMB_SERVICE_H_
#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include "base/files/file.h"
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/ash/file_system_provider/provided_file_system_info.h"
#include "chrome/browser/ash/file_system_provider/provider_interface.h"
#include "chrome/browser/ash/file_system_provider/service.h"
#include "chrome/browser/ash/smb_client/smb_errors.h"
#include "chrome/browser/ash/smb_client/smb_persisted_share_registry.h"
#include "chrome/browser/ash/smb_client/smb_share_finder.h"
#include "chrome/browser/ash/smb_client/smbfs_share.h"
#include "chrome/browser/profiles/profile.h"
#include "chromeos/ash/components/dbus/smbprovider/smb_provider_client.h"
#include "components/keyed_service/core/keyed_service.h"
#include "net/base/network_change_notifier.h"
namespace base {
class FilePath;
} // namespace base
namespace user_prefs {
class PrefRegistrySyncable;
} // namespace user_prefs
namespace ash::smb_client {
class SmbKerberosCredentialsUpdater;
class SmbShareInfo;
// Creates and manages an smb file system.
class SmbService : public KeyedService,
public net::NetworkChangeNotifier::NetworkChangeObserver {
public:
using MountResponse = base::OnceCallback<void(SmbMountResult result)>;
using StartReadDirIfSuccessfulCallback =
base::OnceCallback<void(bool should_retry_start_read_dir)>;
using GatherSharesResponse =
base::RepeatingCallback<void(const std::vector<SmbUrl>& shares_gathered,
bool done)>;
SmbService(Profile* profile, std::unique_ptr<base::TickClock> tick_clock);
SmbService(const SmbService&) = delete;
SmbService& operator=(const SmbService&) = delete;
~SmbService() override;
// KeyedService override.
void Shutdown() override;
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
// Starts the process of mounting an SMB file system. |use_kerberos| indicates
// whether the share should be mounted with a Kerberos ticket - acquired
// though Chromad login or KerberosCredentialsManager.
void Mount(const std::string& display_name,
const base::FilePath& share_path,
const std::string& username,
const std::string& password,
bool use_kerberos,
bool should_open_file_manager_after_mount,
bool save_credentials,
MountResponse callback);
// Unmounts the SmbFs share mounted at |mount_path|.
void UnmountSmbFs(const base::FilePath& mount_path);
// Returns the SmbFsShare instance for the file at |path|. If |path| is not
// part of an smbfs share, returns nullptr.
SmbFsShare* GetSmbFsShareForPath(const base::FilePath& path);
// Gathers the hosts in the network using |share_finder_| and gets the shares
// for each of the hosts found. |discovery_callback| is called as soon as host
// discovery is complete. |shares_callback| may be called multiple times with
// new shares. |shares_callback| will be called with |done| == false when more
// shares are expected to be discovered. When share discovery is finished,
// |shares_callback| is called with |done| == true and will not be called
// again.
void GatherSharesInNetwork(HostDiscoveryResponse discovery_callback,
GatherSharesResponse shares_callback);
// Disable share discovery in test.
static void DisableShareDiscoveryForTesting() {
disable_share_discovery_for_testing_ = true;
}
// Run |callback| when setup had completed. If setup has already completed,
// |callback| will be run inline.
void OnSetupCompleteForTesting(base::OnceClosure callback);
// Sets up Kerberos / AD services.
void SetupKerberos(const std::string& account_identifier);
// Updates credentials for Kerberos service.
void UpdateKerberosCredentials(const std::string& account_identifier);
// Returns true if the Kerberos feature is enabled.
bool IsKerberosEnabledViaPolicy() const;
// Sets the mounter creation callback, which is passed to
// SmbFsShare::SetMounterCreationCallbackForTest() when a new SmbFs share is
// created.
void SetSmbFsMounterCreationCallbackForTesting(
SmbFsShare::MounterCreationCallback callback);
// Returns true if any SMB shares have been configured or saved before.
bool IsAnySmbShareConfigured();
private:
FRIEND_TEST_ALL_PREFIXES(SmbServiceWithSmbfsTest, MountInvalidSaved);
FRIEND_TEST_ALL_PREFIXES(SmbServiceWithSmbfsTest, MountInvalidPreconfigured);
using MountInternalCallback =
base::OnceCallback<void(SmbMountResult result,
const base::FilePath& mount_path)>;
// Callback passed to MountInternal() when mounts are initiated
// (generally by user interaction) via Mount().
void OnUserInitiatedMountDone(MountResponse callback,
const SmbShareInfo& info,
bool should_open_file_manager_after_mount,
SmbMountResult result,
const base::FilePath& mount_path);
// Mounts an SMB share with url |share_url| using either smbprovider or smbfs
// based on feature flags.
// Calls SmbProviderClient::Mount() or start the smbfs mount process.
void MountInternal(const SmbShareInfo& info,
const std::string& password,
bool save_credentials,
bool skip_connect,
MountInternalCallback callback);
// Handles the response from mounting an smbfs share. Passes |result| onto
// |callback|.
void OnSmbfsMountDone(const std::string& smbfs_mount_id,
MountInternalCallback callback,
SmbMountResult result);
file_system_provider::Service* GetProviderService() const;
SmbProviderClient* GetSmbProviderClient() const;
// Attempts to restore any previously mounted shares remembered by the File
// System Provider.
void RestoreMounts();
void OnHostsDiscovered(
const std::vector<SmbShareInfo>& saved_smbfs_shares,
const std::vector<SmbUrl>& preconfigured_shares);
// Sets the callback passed to MountInternal() when a saved or
// preconfigured share mount request is made during setup.
void SetRestoredShareMountDoneCallbackForTesting(
MountInternalCallback callback);
// Mounts a saved (smbfs) SMB share with details |info|.
void MountSavedSmbfsShare(const SmbShareInfo& info);
// Handles the response from attempting to mount a previously saved share.
void OnMountSavedSmbfsShareDone(SmbMountResult result,
const base::FilePath& mount_path);
// Mounts a preconfigured (by policy) SMB share with path |share_url|. The
// share is mounted with empty credentials.
void MountPreconfiguredShare(const SmbUrl& share_url);
// Handles the response from attempting to mount a share configured via
// policy.
void OnMountPreconfiguredShareDone(SmbMountResult result,
const base::FilePath& mount_path);
// Completes SmbService setup including ShareFinder initialization and
// remounting shares.
void CompleteSetup();
// Handles the response from attempting to setup Kerberos.
void OnSetupKerberosResponse(bool success);
// Handles the response from attempting to update Kerberos credentials.
void OnUpdateKerberosCredentialsResponse(bool success);
// Registers host locators for |share_finder_|.
void RegisterHostLocators();
// Set up Multicast DNS host locator.
void SetUpMdnsHostLocator();
// Set up NetBios host locator.
void SetUpNetBiosHostLocator();
// Whether NetBios discovery should be used. Controlled via policy.
bool IsNetBiosDiscoveryEnabled() const;
// Whether NTLM should be used. Controlled via policy.
bool IsNTLMAuthenticationEnabled() const;
// Whether |share| is already mounted.
bool IsShareMounted(const SmbUrl& share) const;
// Gets the list of all shares preconfigured via policy with mode
// |policy_mode|. If |policy_mode| is "unknown", returns a list of all shares
// preconfigured with a mode that does not match any currently known mode.
// This can occur if a new policy is added not yet supported by CrOS.
std::vector<SmbUrl> GetPreconfiguredSharePaths(
const std::string& policy_mode) const;
// Gets the shares preconfigured via policy that should be displayed in the
// discovery dropdown. This includes shares that are explicitly set to be
// shown in the dropdown as well as shares configured with an unrecognized
// mode.
std::vector<SmbUrl> GetPreconfiguredSharePathsForDropdown() const;
// Gets the shares preconfigured via policy that should be premounted.
std::vector<SmbUrl> GetPreconfiguredSharePathsForPremount() const;
// Handles the callback for SmbFsShare::RemoveSavedCredentials().
void OnSmbfsRemoveSavedCredentialsDone(const std::string& mount_id,
bool success);
// NetworkChangeNotifier::NetworkChangeObserver override. Runs HostDiscovery
// when network detects a change.
void OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType type) override;
// Records metrics on the number of SMB mounts a user has.
void RecordMountCount() const;
static bool disable_share_discovery_for_testing_;
const file_system_provider::ProviderId provider_id_;
raw_ptr<Profile> profile_;
std::unique_ptr<SmbShareFinder> share_finder_;
// |smbfs_mount_id| -> SmbFsShare
// Note, mount ID for smbfs is a randomly generated string. For smbprovider
// shares, it is an integer.
std::unordered_map<std::string, std::unique_ptr<SmbFsShare>> smbfs_shares_;
SmbPersistedShareRegistry registry_;
std::unique_ptr<SmbKerberosCredentialsUpdater> kerberos_credentials_updater_;
base::OnceClosure setup_complete_callback_;
SmbFsShare::MounterCreationCallback smbfs_mounter_creation_callback_;
MountInternalCallback restored_share_mount_done_callback_;
base::WeakPtrFactory<SmbService> weak_ptr_factory_{this};
};
} // namespace ash::smb_client
#endif // CHROME_BROWSER_ASH_SMB_CLIENT_SMB_SERVICE_H_