smbfs_mounter.cc 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // Copyright 2019 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. #include "ash/components/smbfs/smbfs_mounter.h"
  5. #include <utility>
  6. #include "base/files/file_util.h"
  7. #include "base/logging.h"
  8. #include "base/strings/strcat.h"
  9. #include "chromeos/components/mojo_bootstrap/pending_connection_manager.h"
  10. #include "mojo/public/cpp/bindings/pending_remote.h"
  11. #include "mojo/public/cpp/system/platform_handle.h"
  12. namespace smbfs {
  13. namespace {
  14. constexpr char kMountUrlPrefix[] = "smbfs://";
  15. constexpr base::TimeDelta kMountTimeout = base::Seconds(20);
  16. } // namespace
  17. SmbFsMounter::KerberosOptions::KerberosOptions(Source source,
  18. const std::string& identity)
  19. : source(source), identity(identity) {
  20. DCHECK(source == Source::kActiveDirectory || source == Source::kKerberos);
  21. DCHECK(!identity.empty());
  22. }
  23. SmbFsMounter::KerberosOptions::~KerberosOptions() = default;
  24. SmbFsMounter::MountOptions::MountOptions() = default;
  25. SmbFsMounter::MountOptions::MountOptions(const MountOptions&) = default;
  26. SmbFsMounter::MountOptions::~MountOptions() = default;
  27. SmbFsMounter::SmbFsMounter(const std::string& share_path,
  28. const std::string& mount_dir_name,
  29. const MountOptions& options,
  30. SmbFsHost::Delegate* delegate,
  31. ash::disks::DiskMountManager* disk_mount_manager)
  32. : SmbFsMounter(share_path,
  33. mount_dir_name,
  34. options,
  35. delegate,
  36. disk_mount_manager,
  37. {}) {}
  38. SmbFsMounter::SmbFsMounter(const std::string& share_path,
  39. const std::string& mount_dir_name,
  40. const MountOptions& options,
  41. SmbFsHost::Delegate* delegate,
  42. ash::disks::DiskMountManager* disk_mount_manager,
  43. mojo::Remote<mojom::SmbFsBootstrap> bootstrap)
  44. : share_path_(share_path),
  45. mount_dir_name_(mount_dir_name),
  46. options_(options),
  47. delegate_(delegate),
  48. disk_mount_manager_(disk_mount_manager),
  49. token_(base::UnguessableToken::Create()),
  50. mount_url_(base::StrCat({kMountUrlPrefix, token_.ToString()})),
  51. bootstrap_(std::move(bootstrap)) {
  52. DCHECK(delegate_);
  53. DCHECK(disk_mount_manager_);
  54. }
  55. SmbFsMounter::SmbFsMounter()
  56. : delegate_(nullptr), disk_mount_manager_(nullptr) {}
  57. SmbFsMounter::~SmbFsMounter() {
  58. if (mojo_fd_pending_) {
  59. mojo_bootstrap::PendingConnectionManager::Get()
  60. .CancelExpectedOpenIpcChannel(token_);
  61. }
  62. }
  63. void SmbFsMounter::Mount(SmbFsMounter::DoneCallback callback) {
  64. DCHECK(!callback_);
  65. DCHECK(callback);
  66. CHECK(!mojo_fd_pending_);
  67. callback_ = std::move(callback);
  68. // If |bootstrap_| is already bound, it was provided by a test subclass.
  69. if (!bootstrap_) {
  70. mojo_bootstrap::PendingConnectionManager::Get().ExpectOpenIpcChannel(
  71. token_,
  72. base::BindOnce(&SmbFsMounter::OnIpcChannel, base::Unretained(this)));
  73. mojo_fd_pending_ = true;
  74. bootstrap_.Bind(mojo::PendingRemote<mojom::SmbFsBootstrap>(
  75. bootstrap_invitation_.AttachMessagePipe(mojom::kBootstrapPipeName),
  76. mojom::SmbFsBootstrap::Version_));
  77. }
  78. bootstrap_.set_disconnect_handler(
  79. base::BindOnce(&SmbFsMounter::OnMojoDisconnect, base::Unretained(this)));
  80. ash::disks::MountPoint::Mount(
  81. disk_mount_manager_, mount_url_, "" /* source_format */, mount_dir_name_,
  82. {} /* mount_options */, ash::MountType::kNetworkStorage,
  83. ash::MountAccessMode::kReadWrite,
  84. base::BindOnce(&SmbFsMounter::OnMountDone, weak_factory_.GetWeakPtr()));
  85. mount_timer_.Start(
  86. FROM_HERE, kMountTimeout,
  87. base::BindOnce(&SmbFsMounter::OnMountTimeout, base::Unretained(this)));
  88. }
  89. void SmbFsMounter::OnMountDone(
  90. ash::MountError error_code,
  91. std::unique_ptr<ash::disks::MountPoint> mount_point) {
  92. if (!callback_) {
  93. // This can happen if the mount timeout expires and the callback is already
  94. // run with a timeout error.
  95. return;
  96. }
  97. if (error_code != ash::MountError::kNone) {
  98. LOG(WARNING) << "smbfs mount error: " << error_code;
  99. ProcessMountError(mojom::MountError::kUnknown);
  100. return;
  101. }
  102. DCHECK(mount_point);
  103. mount_point_ = std::move(mount_point);
  104. mojom::MountOptionsPtr mount_options = mojom::MountOptions::New();
  105. mount_options->share_path = share_path_;
  106. if (options_.resolved_host.IsIPv4()) {
  107. // TODO(crbug.com/1051291): Support IPv6.
  108. mount_options->resolved_host = options_.resolved_host;
  109. }
  110. mount_options->username = options_.username;
  111. mount_options->workgroup = options_.workgroup;
  112. mount_options->allow_ntlm = options_.allow_ntlm;
  113. mount_options->skip_connect = options_.skip_connect;
  114. if (options_.save_restore_password) {
  115. DCHECK_GE(
  116. options_.password_salt.size(),
  117. static_cast<size_t>(mojom::CredentialStorageOptions::kMinSaltLength));
  118. mount_options->credential_storage_options =
  119. mojom::CredentialStorageOptions::New(options_.account_hash,
  120. options_.password_salt);
  121. }
  122. if (options_.kerberos_options) {
  123. mojom::KerberosConfigPtr kerberos_config = mojom::KerberosConfig::New();
  124. kerberos_config->source = options_.kerberos_options->source;
  125. kerberos_config->identity = options_.kerberos_options->identity;
  126. mount_options->kerberos_config = std::move(kerberos_config);
  127. } else if (!options_.password.empty()) {
  128. if (options_.password.size() > mojom::Password::kMaxLength) {
  129. LOG(WARNING) << "smbfs password too long";
  130. ProcessMountError(mojom::MountError::kUnknown);
  131. return;
  132. }
  133. int pipe_fds[2];
  134. CHECK(base::CreateLocalNonBlockingPipe(pipe_fds));
  135. base::ScopedFD pipe_read_end(pipe_fds[0]);
  136. base::ScopedFD pipe_write_end(pipe_fds[1]);
  137. // Write password to pipe.
  138. CHECK(base::WriteFileDescriptor(pipe_write_end.get(), options_.password));
  139. mojom::PasswordPtr password = mojom::Password::New();
  140. password->length = static_cast<int32_t>(options_.password.size());
  141. password->fd = mojo::WrapPlatformHandle(
  142. mojo::PlatformHandle(std::move(pipe_read_end)));
  143. mount_options->password = std::move(password);
  144. }
  145. mojo::PendingRemote<mojom::SmbFsDelegate> delegate_remote;
  146. mojo::PendingReceiver<mojom::SmbFsDelegate> delegate_receiver =
  147. delegate_remote.InitWithNewPipeAndPassReceiver();
  148. bootstrap_->MountShare(
  149. std::move(mount_options), std::move(delegate_remote),
  150. base::BindOnce(&SmbFsMounter::OnMountShare, base::Unretained(this),
  151. std::move(delegate_receiver)));
  152. }
  153. void SmbFsMounter::OnIpcChannel(base::ScopedFD mojo_fd) {
  154. DCHECK(mojo_fd.is_valid());
  155. mojo::OutgoingInvitation::Send(
  156. std::move(bootstrap_invitation_), base::kNullProcessHandle,
  157. mojo::PlatformChannelEndpoint(mojo::PlatformHandle(std::move(mojo_fd))));
  158. mojo_fd_pending_ = false;
  159. }
  160. void SmbFsMounter::OnMountShare(
  161. mojo::PendingReceiver<mojom::SmbFsDelegate> delegate_receiver,
  162. mojom::MountError mount_error,
  163. mojo::PendingRemote<mojom::SmbFs> smbfs) {
  164. if (!callback_) {
  165. return;
  166. }
  167. if (mount_error != mojom::MountError::kOk) {
  168. LOG(WARNING) << "smbfs mount share error: " << mount_error;
  169. ProcessMountError(mount_error);
  170. return;
  171. }
  172. DCHECK(mount_point_);
  173. std::unique_ptr<SmbFsHost> host =
  174. std::make_unique<SmbFsHost>(std::move(mount_point_), delegate_,
  175. mojo::Remote<mojom::SmbFs>(std::move(smbfs)),
  176. std::move(delegate_receiver));
  177. std::move(callback_).Run(mojom::MountError::kOk, std::move(host));
  178. }
  179. void SmbFsMounter::OnMojoDisconnect() {
  180. if (!callback_) {
  181. return;
  182. }
  183. LOG(WARNING) << "smbfs bootstrap disconnection";
  184. ProcessMountError(mojom::MountError::kUnknown);
  185. }
  186. void SmbFsMounter::OnMountTimeout() {
  187. if (!callback_) {
  188. return;
  189. }
  190. LOG(ERROR) << "smbfs mount timeout";
  191. ProcessMountError(mojom::MountError::kTimeout);
  192. }
  193. void SmbFsMounter::ProcessMountError(mojom::MountError mount_error) {
  194. mount_point_.reset();
  195. std::move(callback_).Run(mount_error, nullptr);
  196. }
  197. } // namespace smbfs