1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_CHROMEOS_SMB_CLIENT_SMB_SERVICE_H_ 6 #define CHROME_BROWSER_CHROMEOS_SMB_CLIENT_SMB_SERVICE_H_ 7 8 #include <map> 9 #include <memory> 10 #include <string> 11 #include <unordered_map> 12 #include <vector> 13 14 #include "base/callback.h" 15 #include "base/files/file.h" 16 #include "base/macros.h" 17 #include "base/memory/weak_ptr.h" 18 #include "base/time/time.h" 19 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h" 20 #include "chrome/browser/chromeos/file_system_provider/provider_interface.h" 21 #include "chrome/browser/chromeos/file_system_provider/service.h" 22 #include "chrome/browser/chromeos/smb_client/smb_errors.h" 23 #include "chrome/browser/chromeos/smb_client/smb_persisted_share_registry.h" 24 #include "chrome/browser/chromeos/smb_client/smb_share_finder.h" 25 #include "chrome/browser/chromeos/smb_client/smb_task_queue.h" 26 #include "chrome/browser/chromeos/smb_client/smbfs_share.h" 27 #include "chrome/browser/profiles/profile.h" 28 #include "chromeos/dbus/power/power_manager_client.h" 29 #include "chromeos/dbus/smb_provider_client.h" 30 #include "components/keyed_service/core/keyed_service.h" 31 #include "net/base/network_change_notifier.h" 32 33 namespace base { 34 class FilePath; 35 } // namespace base 36 37 namespace user_prefs { 38 class PrefRegistrySyncable; 39 } // namespace user_prefs 40 41 namespace chromeos { 42 namespace smb_client { 43 44 using file_system_provider::ProvidedFileSystemInfo; 45 46 class SmbKerberosCredentialsUpdater; 47 class SmbShareInfo; 48 49 // Creates and manages an smb file system. 50 class SmbService : public KeyedService, 51 public net::NetworkChangeNotifier::NetworkChangeObserver, 52 public chromeos::PowerManagerClient::Observer, 53 public base::SupportsWeakPtr<SmbService> { 54 public: 55 using MountResponse = base::OnceCallback<void(SmbMountResult result)>; 56 using StartReadDirIfSuccessfulCallback = 57 base::OnceCallback<void(bool should_retry_start_read_dir)>; 58 using GatherSharesResponse = 59 base::RepeatingCallback<void(const std::vector<SmbUrl>& shares_gathered, 60 bool done)>; 61 62 SmbService(Profile* profile, std::unique_ptr<base::TickClock> tick_clock); 63 ~SmbService() override; 64 65 // KeyedService override. 66 void Shutdown() override; 67 68 static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); 69 70 // Starts the process of mounting an SMB file system. 71 // |use_kerberos| indicates whether the share should be mounted with a user's 72 // chromad kerberos tickets. 73 void Mount(const file_system_provider::MountOptions& options, 74 const base::FilePath& share_path, 75 const std::string& username, 76 const std::string& password, 77 bool use_kerberos, 78 bool should_open_file_manager_after_mount, 79 bool save_credentials, 80 MountResponse callback); 81 82 // Unmounts the SmbFs share mounted at |mount_path|. 83 void UnmountSmbFs(const base::FilePath& mount_path); 84 85 // Returns the SmbFsShare instance for the file at |path|. If |path| is not 86 // part of an smbfs share, returns nullptr. 87 SmbFsShare* GetSmbFsShareForPath(const base::FilePath& path); 88 89 // Gathers the hosts in the network using |share_finder_| and gets the shares 90 // for each of the hosts found. |discovery_callback| is called as soon as host 91 // discovery is complete. |shares_callback| may be called multiple times with 92 // new shares. |shares_callback| will be called with |done| == false when more 93 // shares are expected to be discovered. When share discovery is finished, 94 // |shares_callback| is called with |done| == true and will not be called 95 // again. 96 void GatherSharesInNetwork(HostDiscoveryResponse discovery_callback, 97 GatherSharesResponse shares_callback); 98 99 // Updates the share path for |mount_id|. 100 void UpdateSharePath(int32_t mount_id, 101 const std::string& share_path, 102 StartReadDirIfSuccessfulCallback reply); 103 104 // Disable share discovery in test. DisableShareDiscoveryForTesting()105 static void DisableShareDiscoveryForTesting() { 106 disable_share_discovery_for_testing_ = true; 107 } 108 109 // Run |callback| when setup had completed. If setup has already completed, 110 // |callback| will be run inline. 111 void OnSetupCompleteForTesting(base::OnceClosure callback); 112 113 // Sets up Kerberos / AD services. 114 void SetupKerberos(const std::string& account_identifier); 115 116 // Updates credentials for Kerberos service. 117 void UpdateKerberosCredentials(const std::string& account_identifier); 118 119 // Returns true if Kerberos was enabled via policy at service creation time 120 // and is still enabled now. 121 bool IsKerberosEnabledViaPolicy() const; 122 123 // Sets the mounter creation callback, which is passed to 124 // SmbFsShare::SetMounterCreationCallbackForTest() when a new SmbFs share is 125 // created. 126 void SetSmbFsMounterCreationCallbackForTesting( 127 SmbFsShare::MounterCreationCallback callback); 128 129 // chromeos::PowerManagerClient::Observer overrides 130 void SuspendImminent(power_manager::SuspendImminent::Reason reason) override; 131 void SuspendDone(const base::TimeDelta& sleep_duration) override; 132 133 private: 134 friend class SmbServiceTest; 135 136 using MountInternalCallback = 137 base::OnceCallback<void(SmbMountResult result, 138 const base::FilePath& mount_path)>; 139 140 // Callback passed to MountInternal(). 141 void MountInternalDone(MountResponse callback, 142 const SmbShareInfo& info, 143 bool should_open_file_manager_after_mount, 144 SmbMountResult result, 145 const base::FilePath& mount_path); 146 147 // Mounts an SMB share with url |share_url| using either smbprovider or smbfs 148 // based on feature flags. 149 // Calls SmbProviderClient::Mount() or start the smbfs mount process. 150 void MountInternal(const file_system_provider::MountOptions& options, 151 const SmbShareInfo& info, 152 const std::string& password, 153 bool save_credentials, 154 bool skip_connect, 155 MountInternalCallback callback); 156 157 // Handles the response from mounting an SMB share using smbprovider. 158 // Completes the mounting of an SMB file system, passing |options| on to 159 // file_system_provider::Service::MountFileSystem(). Passes error status to 160 // callback. 161 void OnProviderMountDone(MountInternalCallback callback, 162 const file_system_provider::MountOptions& options, 163 bool save_credentials, 164 smbprovider::ErrorType error, 165 int32_t mount_id); 166 167 // Handles the response from mounting an smbfs share. Passes |result| onto 168 // |callback|. 169 void OnSmbfsMountDone(const std::string& smbfs_mount_id, 170 MountInternalCallback callback, 171 SmbMountResult result); 172 173 // Callback passed to SmbFsShare::Unmount() during a power management 174 // suspension. Ensures that suspension is blocked until the unmount completes. 175 void OnSuspendUnmountDone(base::UnguessableToken power_manager_suspend_token, 176 chromeos::MountError result); 177 178 // Retrieves the mount_id for |file_system_info|. 179 int32_t GetMountId(const ProvidedFileSystemInfo& info) const; 180 181 // Calls file_system_provider::Service::UnmountFileSystem(). 182 base::File::Error Unmount( 183 const std::string& file_system_id, 184 file_system_provider::Service::UnmountReason reason); 185 186 file_system_provider::Service* GetProviderService() const; 187 188 SmbProviderClient* GetSmbProviderClient() const; 189 190 // Attempts to restore any previously mounted shares remembered by the File 191 // System Provider. 192 void RestoreMounts(); 193 194 void OnHostsDiscovered( 195 const std::vector<ProvidedFileSystemInfo>& file_systems, 196 const std::vector<SmbShareInfo>& saved_smbfs_shares, 197 const std::vector<SmbUrl>& preconfigured_shares); 198 199 // Closure for OnHostDiscovered(). |reply| is passed down to 200 // UpdateSharePath(). 201 void OnHostsDiscoveredForUpdateSharePath( 202 int32_t mount_id, 203 const std::string& share_path, 204 StartReadDirIfSuccessfulCallback reply); 205 206 // Attempts to remount a share with the information in |file_system_info|. 207 void Remount(const ProvidedFileSystemInfo& file_system_info); 208 209 // Handles the response from attempting to remount the file system. If 210 // remounting fails, this logs and removes the file_system from the volume 211 // manager. 212 void OnRemountResponse(const std::string& file_system_id, 213 smbprovider::ErrorType error, 214 int32_t mount_id); 215 216 // Mounts a saved (smbfs) SMB share with details |info|. 217 void MountSavedSmbfsShare(const SmbShareInfo& info); 218 219 // Mounts a preconfigured (by policy) SMB share with path |share_url|. The 220 // share is mounted with empty credentials. 221 void MountPreconfiguredShare(const SmbUrl& share_url); 222 223 // Handles the response from attempting to mount a share configured via 224 // policy. 225 void OnMountPreconfiguredShareDone(SmbMountResult result, 226 const base::FilePath& mount_path); 227 228 // Completes SmbService setup including ShareFinder initialization and 229 // remounting shares. 230 void CompleteSetup(); 231 232 // Handles the response from attempting to setup Kerberos. 233 void OnSetupKerberosResponse(bool success); 234 235 // Handles the response from attempting to update Kerberos credentials. 236 void OnUpdateKerberosCredentialsResponse(bool success); 237 238 // Registers host locators for |share_finder_|. 239 void RegisterHostLocators(); 240 241 // Set up Multicast DNS host locator. 242 void SetUpMdnsHostLocator(); 243 244 // Set up NetBios host locator. 245 void SetUpNetBiosHostLocator(); 246 247 // Whether NetBios discovery should be used. Controlled via policy. 248 bool IsNetBiosDiscoveryEnabled() const; 249 250 // Whether NTLM should be used. Controlled via policy. 251 bool IsNTLMAuthenticationEnabled() const; 252 253 // Whether |share| is already mounted. 254 bool IsShareMounted(const SmbUrl& share) const; 255 256 // Gets the list of all shares preconfigured via policy with mode 257 // |policy_mode|. If |policy_mode| is "unknown", returns a list of all shares 258 // preconfigured with a mode that does not match any currently known mode. 259 // This can occur if a new policy is added not yet supported by CrOS. 260 std::vector<SmbUrl> GetPreconfiguredSharePaths( 261 const std::string& policy_mode) const; 262 263 // Gets the shares preconfigured via policy that should be displayed in the 264 // discovery dropdown. This includes shares that are explicitly set to be 265 // shown in the dropdown as well as shares configured with an unrecognized 266 // mode. 267 std::vector<SmbUrl> GetPreconfiguredSharePathsForDropdown() const; 268 269 // Gets the shares preconfigured via policy that should be premounted. 270 std::vector<SmbUrl> GetPreconfiguredSharePathsForPremount() const; 271 272 // Requests new credentials for the |share_path|. |reply| is stored. Once the 273 // credentials have been successfully updated, |reply| is run. 274 void RequestCredentials(const std::string& share_path, 275 int32_t mount_id, 276 base::OnceClosure reply); 277 278 // Handles the response from showing the SMB credentials dialog. If |canceled| 279 // is true, the |reply| callback is dropped. Otherwise, |username| and 280 // |password| are passed to the smb service and |reply| is run if the service 281 // returns success. 282 void OnSmbCredentialsDialogShown(int32_t mount_id, 283 base::OnceClosure reply, 284 bool canceled, 285 const std::string& username, 286 const std::string& password); 287 288 // Requests an updated share path via running 289 // ShareFinder::DiscoverHostsInNetwork. |reply| is stored. Once the share path 290 // has been successfully updated, |reply| is run. 291 void RequestUpdatedSharePath(const std::string& share_path, 292 int32_t mount_id, 293 StartReadDirIfSuccessfulCallback reply); 294 295 // Handles the response for attempting to update the share path of a mount. 296 // |reply| will run if |error| is ERROR_OK. Logs the error otherwise. 297 void OnUpdateSharePathResponse(int32_t mount_id, 298 StartReadDirIfSuccessfulCallback reply, 299 smbprovider::ErrorType error); 300 301 // Handles the callback for SmbFsShare::RemoveSavedCredentials(). 302 void OnSmbfsRemoveSavedCredentialsDone(const std::string& mount_id, 303 bool success); 304 305 // Helper function that determines if HostDiscovery can be run again. Returns 306 // false if HostDiscovery was recently run. 307 bool ShouldRunHostDiscoveryAgain() const; 308 309 // NetworkChangeNotifier::NetworkChangeObserver override. Runs HostDiscovery 310 // when network detects a change. 311 void OnNetworkChanged( 312 net::NetworkChangeNotifier::ConnectionType type) override; 313 314 // Records metrics on the number of SMB mounts a user has. 315 void RecordMountCount() const; 316 317 static bool disable_share_discovery_for_testing_; 318 319 base::TimeTicks previous_host_discovery_time_; 320 const file_system_provider::ProviderId provider_id_; 321 Profile* profile_; 322 std::unique_ptr<base::TickClock> tick_clock_; 323 std::unique_ptr<SmbShareFinder> share_finder_; 324 // |file_system_id| -> |mount_id| 325 std::unordered_map<std::string, int32_t> mount_id_map_; 326 // |smbfs_mount_id| -> SmbFsShare 327 // Note, mount ID for smbfs is a randomly generated string. For smbprovider 328 // shares, it is an integer. 329 std::unordered_map<std::string, std::unique_ptr<SmbFsShare>> smbfs_shares_; 330 SmbPersistedShareRegistry registry_; 331 332 std::unique_ptr<SmbKerberosCredentialsUpdater> smb_credentials_updater_; 333 334 base::OnceClosure setup_complete_callback_; 335 SmbFsShare::MounterCreationCallback smbfs_mounter_creation_callback_; 336 337 DISALLOW_COPY_AND_ASSIGN(SmbService); 338 }; 339 340 } // namespace smb_client 341 } // namespace chromeos 342 343 #endif // CHROME_BROWSER_CHROMEOS_SMB_CLIENT_SMB_SERVICE_H_ 344