This prevents credential information from being persisted into the local data directory which is used during subsequent runs to determine folder definition changes.
187 lines
5.7 KiB
Ruby
187 lines
5.7 KiB
Ruby
require "digest/md5"
|
|
require "json"
|
|
|
|
require "log4r"
|
|
|
|
require "vagrant/util/platform"
|
|
require "vagrant/util/powershell"
|
|
|
|
require_relative "errors"
|
|
|
|
module VagrantPlugins
|
|
module SyncedFolderSMB
|
|
class SyncedFolder < Vagrant.plugin("2", :synced_folder)
|
|
|
|
# Maximum number of times to retry requesting username/password
|
|
CREDENTIAL_RETRY_MAX = 5
|
|
|
|
def initialize(*args)
|
|
super
|
|
|
|
@logger = Log4r::Logger.new("vagrant::synced_folders::smb")
|
|
end
|
|
|
|
def usable?(machine, raise_error=false)
|
|
# If the machine explicitly states SMB is not supported, then
|
|
# believe it
|
|
return false if !machine.config.smb.functional
|
|
return true if machine.env.host.capability?(:smb_installed) &&
|
|
machine.env.host.capability(:smb_installed)
|
|
return false if !raise_error
|
|
raise Errors::SMBNotSupported
|
|
end
|
|
|
|
def prepare(machine, folders, opts)
|
|
machine.ui.output(I18n.t("vagrant_sf_smb.preparing"))
|
|
|
|
smb_username = smb_password = nil
|
|
|
|
# If we need auth information, then ask the user.
|
|
have_auth = false
|
|
folders.each do |id, data|
|
|
smb_username = data[:smb_username] if data[:smb_username]
|
|
smb_password = data[:smb_password] if data[:smb_password]
|
|
if smb_username && smb_password
|
|
have_auth = true
|
|
break
|
|
end
|
|
end
|
|
|
|
modify_username = false
|
|
if !have_auth
|
|
machine.ui.detail(I18n.t("vagrant_sf_smb.warning_password") + "\n ")
|
|
retries = 0
|
|
while retries < CREDENTIAL_RETRY_MAX do
|
|
if smb_username
|
|
username = machine.ui.ask("Username (#{smb_username}): ")
|
|
smb_username = username if username != ""
|
|
modify_username = true
|
|
else
|
|
smb_username = machine.ui.ask("Username: ")
|
|
end
|
|
|
|
smb_password = machine.ui.ask("Password (will be hidden): ", echo: false)
|
|
auth_success = true
|
|
|
|
if machine.env.host.capability?(:smb_validate_password)
|
|
Vagrant::Util::CredentialScrubber.sensitive(smb_password)
|
|
auth_success = machine.env.host.capability(:smb_validate_password,
|
|
smb_username, smb_password)
|
|
end
|
|
|
|
break if auth_success
|
|
machine.ui.output(I18n.t("vagrant_sf_smb.incorrect_credentials") + "\n ")
|
|
retries += 1
|
|
end
|
|
|
|
if retries >= CREDENTIAL_RETRY_MAX
|
|
raise Errors::CredentialsRequestError
|
|
end
|
|
end
|
|
|
|
# Check if this host can start and SMB service
|
|
if machine.env.host.capability?(:smb_start)
|
|
machine.env.host.capability(:smb_start)
|
|
end
|
|
|
|
folders.each do |id, data|
|
|
if modify_username
|
|
# Only override original username if user requests to
|
|
data[:smb_username] = smb_username
|
|
else
|
|
data[:smb_username] ||= smb_username
|
|
end
|
|
data[:smb_password] ||= smb_password
|
|
|
|
# Register password as sensitive
|
|
Vagrant::Util::CredentialScrubber.sensitive(data[:smb_password])
|
|
end
|
|
|
|
machine.env.host.capability(:smb_prepare, machine, folders, opts)
|
|
end
|
|
|
|
def enable(machine, folders, opts)
|
|
machine.ui.output(I18n.t("vagrant_sf_smb.mounting"))
|
|
|
|
# Make sure that this machine knows this dance
|
|
if !machine.guest.capability?(:mount_smb_shared_folder)
|
|
raise Vagrant::Errors::GuestCapabilityNotFound,
|
|
cap: "mount_smb_shared_folder",
|
|
guest: machine.guest.name.to_s
|
|
end
|
|
|
|
# Setup if we have it
|
|
if machine.guest.capability?(:smb_install)
|
|
machine.guest.capability(:smb_install)
|
|
end
|
|
|
|
# Detect the host IP for this guest if one wasn't specified
|
|
# for every folder.
|
|
host_ip = nil
|
|
need_host_ip = false
|
|
folders.each do |id, data|
|
|
if !data[:smb_host]
|
|
need_host_ip = true
|
|
break
|
|
end
|
|
end
|
|
|
|
if need_host_ip
|
|
candidate_ips = machine.env.host.capability(:configured_ip_addresses)
|
|
@logger.debug("Potential host IPs: #{candidate_ips.inspect}")
|
|
host_ip = machine.guest.capability(
|
|
:choose_addressable_ip_addr, candidate_ips)
|
|
if !host_ip
|
|
raise Errors::NoHostIPAddr
|
|
end
|
|
end
|
|
|
|
# This is used for defaulting the owner/group
|
|
ssh_info = machine.ssh_info
|
|
|
|
folders.each do |id, data|
|
|
data[:smb_host] ||= host_ip
|
|
|
|
# Default the owner/group of the folder to the SSH user
|
|
data[:owner] ||= ssh_info[:username]
|
|
data[:group] ||= ssh_info[:username]
|
|
|
|
machine.ui.detail(I18n.t(
|
|
"vagrant_sf_smb.mounting_single",
|
|
host: data[:hostpath].to_s,
|
|
guest: data[:guestpath].to_s))
|
|
machine.guest.capability(
|
|
:mount_smb_shared_folder, data[:smb_id], data[:guestpath], data)
|
|
|
|
clean_folder_configuration(data)
|
|
end
|
|
end
|
|
|
|
# Nothing to do here but ensure folder options are scrubbed
|
|
def disable(machine, folders, opts)
|
|
folders.each do |_, data|
|
|
clean_folder_configuration(data)
|
|
end
|
|
end
|
|
|
|
def cleanup(machine, opts)
|
|
if machine.env.host.capability?(:smb_cleanup)
|
|
machine.env.host.capability(:smb_cleanup, machine, opts)
|
|
end
|
|
end
|
|
|
|
protected
|
|
|
|
# Remove data that should not be persisted within folder
|
|
# specific configuration
|
|
#
|
|
# @param [Hash] data Folder configuration
|
|
def clean_folder_configuration(data)
|
|
return if !data.is_a?(Hash)
|
|
data.delete(:smb_password)
|
|
nil
|
|
end
|
|
end
|
|
end
|
|
end
|