From 00fa50c296bda4ea708d2791caae09d627494f27 Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Fri, 15 Dec 2017 16:31:44 -0800 Subject: [PATCH] SMB enhancements --- lib/vagrant/util/powershell.rb | 90 +++++++++++++--- .../linux/cap/mount_smb_shared_folder.rb | 6 +- .../darwin/cap/configured_ip_addresses.rb | 18 ++++ plugins/hosts/darwin/cap/smb.rb | 86 +++++++++++++++ plugins/hosts/darwin/plugin.rb | 25 +++++ .../windows/cap/configured_ip_addresses.rb | 29 +++++ plugins/hosts/windows/cap/smb.rb | 102 ++++++++++++++++++ plugins/hosts/windows/plugin.rb | 20 ++++ .../windows}/scripts/host_info.ps1 | 0 plugins/hosts/windows/scripts/set_share.ps1 | 39 +++++++ plugins/hosts/windows/scripts/unset_share.ps1 | 11 ++ plugins/synced_folders/smb/errors.rb | 4 + .../synced_folders/smb/scripts/set_share.ps1 | 44 -------- plugins/synced_folders/smb/synced_folder.rb | 84 ++++----------- templates/locales/synced_folder_smb.yml | 16 +++ 15 files changed, 452 insertions(+), 122 deletions(-) create mode 100644 plugins/hosts/darwin/cap/configured_ip_addresses.rb create mode 100644 plugins/hosts/darwin/cap/smb.rb create mode 100644 plugins/hosts/windows/cap/configured_ip_addresses.rb create mode 100644 plugins/hosts/windows/cap/smb.rb rename plugins/{synced_folders/smb => hosts/windows}/scripts/host_info.ps1 (100%) create mode 100644 plugins/hosts/windows/scripts/set_share.ps1 create mode 100644 plugins/hosts/windows/scripts/unset_share.ps1 delete mode 100644 plugins/synced_folders/smb/scripts/set_share.ps1 diff --git a/lib/vagrant/util/powershell.rb b/lib/vagrant/util/powershell.rb index b5d474cec..fefb60571 100644 --- a/lib/vagrant/util/powershell.rb +++ b/lib/vagrant/util/powershell.rb @@ -1,3 +1,4 @@ +require "tmpdir" require_relative "subprocess" require_relative "which" @@ -25,21 +26,26 @@ module Vagrant # @return [Subprocess::Result] def self.execute(path, *args, **opts, &block) validate_install! - command = [ - "powershell", - "-NoLogo", - "-NoProfile", - "-NonInteractive", - "-ExecutionPolicy", "Bypass", - "&('#{path}')", - args - ].flatten - # Append on the options hash since Subprocess doesn't use - # Ruby 2.0 style options yet. - command << opts + if opts.delete(:sudo) || opts.delete(:runas) + powerup_command(path, args, opts) + else + command = [ + "powershell", + "-NoLogo", + "-NoProfile", + "-NonInteractive", + "-ExecutionPolicy", "Bypass", + "&('#{path}')", + args + ].flatten - Subprocess.execute(*command, &block) + # Append on the options hash since Subprocess doesn't use + # Ruby 2.0 style options yet. + command << opts + + Subprocess.execute(*command, &block) + end end # Execute a powershell command. @@ -56,7 +62,7 @@ module Vagrant "-ExecutionPolicy", "Bypass", "-Command", command - ].flatten + ].flatten.compact r = Subprocess.execute(*c) return nil if r.exit_code != 0 @@ -75,7 +81,7 @@ module Vagrant "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", - "$PSVersionTable.PSVersion.Major" + "Write-Output $PSVersionTable.PSVersion.Major" ].flatten r = Subprocess.execute(*command) @@ -101,6 +107,60 @@ module Vagrant end @_powershell_validation end + + # Powerup the given command to perform privileged operations. + # + # @param [String] path + # @param [Array] args + # @return [Array] + def self.powerup_command(path, args, opts) + Dir.mktmpdir("vagrant") do |dpath| + all_args = ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", path] + args + arg_list = "@('" + all_args.join("', '") + "')" + stdout = File.join(dpath, "stdout.txt") + stderr = File.join(dpath, "stderr.txt") + exitcode = File.join(dpath, "exitcode.txt") + + script = "$sp = Start-Process -FilePath powershell -ArgumentList #{arg_list} " \ + "-PassThru -Wait -RedirectStandardOutput '#{stdout}' -RedirectStandardError '#{stderr}' -WindowStyle Hidden; " \ + "if($sp){ Set-Content -Path '#{exitcode}' -Value $sp.ExitCode;exit $sp.ExitCode; }else{ exit 1 }" + + # escape quotes so we can nest our script within a start-process + script.gsub!("'", "''") + + cmd = [ + "powershell", + "-NoLogo", + "-NoProfile", + "-NonInteractive", + "-ExecutionPolicy", "Bypass", + "-Command", "$p = Start-Process -FilePath powershell -ArgumentList " \ + "@('-NoLogo', '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-Command', '#{script}') " \ + "-PassThru -Wait -WindowStyle Hidden -Verb RunAs; if($p){ exit $p.ExitCode; }else{ exit 1 }" + ] + + result = Subprocess.execute(*cmd.push(opts)) + if File.exist?(stdout) + r_stdout = File.read(stdout) + else + r_stdout = result.stdout + end + if File.exist?(stderr) + r_stderr = File.read(stderr) + else + r_stderr = result.stderr + end + + code = 1 + if File.exist?(exitcode) + code_txt = File.read(exitcode).strip + if code_txt.match(/^\d+$/) + code = code_txt.to_i + end + end + Subprocess::Result.new(code, r_stdout, r_stderr) + end + end end end end diff --git a/plugins/guests/linux/cap/mount_smb_shared_folder.rb b/plugins/guests/linux/cap/mount_smb_shared_folder.rb index 5389437d2..f2a2cb7c3 100644 --- a/plugins/guests/linux/cap/mount_smb_shared_folder.rb +++ b/plugins/guests/linux/cap/mount_smb_shared_folder.rb @@ -24,7 +24,11 @@ module VagrantPlugins smb_password = options[:smb_password] options[:mount_options] ||= [] - options[:mount_options] << "sec=ntlm" + if machine.env.host.capability?(:smb_mount_options) + options[:mount_options] += machine.env.host.capability(:smb_mount_options) + else + options[:mount_options] << "sec=ntlm" + end options[:mount_options] << "credentials=/etc/smb_creds_#{name}" mount_options = "-o uid=#{mount_uid},gid=#{mount_gid}" diff --git a/plugins/hosts/darwin/cap/configured_ip_addresses.rb b/plugins/hosts/darwin/cap/configured_ip_addresses.rb new file mode 100644 index 000000000..063295ea1 --- /dev/null +++ b/plugins/hosts/darwin/cap/configured_ip_addresses.rb @@ -0,0 +1,18 @@ +require "socket" + +module VagrantPlugins + module HostDarwin + module Cap + class ConfiguredIPAddresses + + def self.configured_ip_addresses(env) + Socket.getifaddrs.map do |interface| + if interface.addr.ipv4? && !interface.addr.ipv4_loopback? + interface.addr.ip_address + end + end.compact + end + end + end + end +end diff --git a/plugins/hosts/darwin/cap/smb.rb b/plugins/hosts/darwin/cap/smb.rb new file mode 100644 index 000000000..ba0ba1e94 --- /dev/null +++ b/plugins/hosts/darwin/cap/smb.rb @@ -0,0 +1,86 @@ +module VagrantPlugins + module HostDarwin + module Cap + class SMB + + @@logger = Log4r::Logger.new("vagrant::host::darwin::smb") + + # If we have the sharing binary available, smb is installed + def self.smb_installed(env) + File.exist?("/usr/sbin/sharing") + end + + # Required options for mounting a share hosted + # on macos. + def self.smb_mount_options(env) + ["ver=3", "sec=ntlmssp", "nounix", "noperm"] + end + + def self.smb_cleanup(env, machine, opts) + m_id = machine_id(machine) + result = Vagrant::Util::Subprocess.execute("/bin/sh", "-c", + "/usr/sbin/sharing -l | grep -E \"^name:.+\\svgt-#{m_id}-\" | awk '{print $2}'") + if result.exit_code != 0 + @@logger.warn("failed to locate any shares for cleanup") + end + shares = result.stdout.split(/\s/).map(&:strip) + @@logger.debug("shares to be removed: #{shares}") + shares.each do |share_name| + @@logger.info("removing share name=#{share_name}") + share_name.strip! + result = Vagrant::Util::Subprocess.execute("/usr/bin/sudo", + "/usr/sbin/sharing", "-r", share_name) + if result.exit_code != 0 + # Removing always returns 0 even if there are currently + # guests attached so if we get a non-zero value just + # log it as unexpected + @@logger.warn("removing share `#{share_name}` returned non-zero") + end + end + end + + def self.smb_prepare(env, machine, folders, opts) + folders.each do |id, data| + hostpath = data[:hostpath] + + chksum_id = Digest::MD5.hexdigest(id) + name = "vgt-#{machine_id(machine)}-#{chksum_id}" + data[:smb_id] ||= name + + @@logger.info("creating new share name=#{name} id=#{data[:smb_id]}") + + cmd = [ + "/usr/bin/sudo", + "/usr/sbin/sharing", + "-a", hostpath, + "-S", data[:smb_id], + "-s", "001", + "-g", "000", + "-n", name + ] + + r = Vagrant::Util::Subprocess.execute(*cmd) + + if r.exit_code != 0 + raise Errors::DefineShareFailed, + host: hostpath.to_s, + stderr: r.stderr, + stdout: r.stdout + end + end + end + + # Generates a unique identifier for the given machine + # based on the name, provider name, and working directory + # of the environment. + # + # @param [Vagrant::Machine] machine + # @return [String] + def self.machine_id(machine) + @@logger.debug("generating machine ID name=#{machine.name} cwd=#{machine.env.cwd}") + Digest::MD5.hexdigest("#{machine.name}-#{machine.provider_name}-#{machine.env.cwd}") + end + end + end + end +end diff --git a/plugins/hosts/darwin/plugin.rb b/plugins/hosts/darwin/plugin.rb index f37bcd9dd..92cb51787 100644 --- a/plugins/hosts/darwin/plugin.rb +++ b/plugins/hosts/darwin/plugin.rb @@ -20,6 +20,31 @@ module VagrantPlugins require_relative "cap/rdp" Cap::RDP end + + host_capability("darwin", "smb_installed") do + require_relative "cap/smb" + Cap::SMB + end + + host_capability("darwin", "smb_prepare") do + require_relative "cap/smb" + Cap::SMB + end + + host_capability("darwin", "smb_mount_options") do + require_relative "cap/smb" + Cap::SMB + end + + host_capability("darwin", "smb_cleanup") do + require_relative "cap/smb" + Cap::SMB + end + + host_capability("darwin", "configured_ip_addresses") do + require_relative "cap/configured_ip_addresses" + Cap::ConfiguredIPAddresses + end end end end diff --git a/plugins/hosts/windows/cap/configured_ip_addresses.rb b/plugins/hosts/windows/cap/configured_ip_addresses.rb new file mode 100644 index 000000000..43820cb5a --- /dev/null +++ b/plugins/hosts/windows/cap/configured_ip_addresses.rb @@ -0,0 +1,29 @@ +require "pathname" +require "tempfile" + +require "vagrant/util/downloader" +require "vagrant/util/file_checksum" +require "vagrant/util/powershell" +require "vagrant/util/subprocess" + +module VagrantPlugins + module HostWindows + module Cap + class ConfiguredIPAddresses + + def self.configured_ip_addresses(env) + script_path = File.expand_path("../../scripts/host_info.ps1", __FILE__) + r = Vagrant::Util::PowerShell.execute(script_path) + if r.exit_code != 0 + raise Errors::PowershellError, + script: script_path, + stderr: r.stderr + end + + res = JSON.parse(r.stdout)["ip_addresses"] + Array(res) + end + end + end + end +end diff --git a/plugins/hosts/windows/cap/smb.rb b/plugins/hosts/windows/cap/smb.rb new file mode 100644 index 000000000..b990abba3 --- /dev/null +++ b/plugins/hosts/windows/cap/smb.rb @@ -0,0 +1,102 @@ +module VagrantPlugins + module HostWindows + module Cap + class SMB + + # Number of seconds to display UAC warning to user + UAC_PROMPT_WAIT = 4 + + @@logger = Log4r::Logger.new("vagrant::host::windows::smb") + + def self.smb_installed(env) + psv = Vagrant::Util::PowerShell.version.to_i + if psv < 3 + if raise_error + raise SyncedFolderSMB::Errors::PowershellVersion, + version: psv.to_s + end + return false + end + + true + end + + def self.smb_cleanup(env, machine, opts) + script_path = File.expand_path("../../scripts/unset_share.ps1", __FILE__) + + m_id = machine_id(machine) + result = Vagrant::Util::PowerShell.execute_cmd("net share") + if result.nil? + @@logger.warn("failed to get current share list") + return + end + prune_shares = result.split("\n").map do |line| + sections = line.split(/\s/) + if sections.first.to_s.start_with?("vgt-#{m_id}") + sections.first + end + end.compact + @@logger.debug("shares to be removed: #{prune_shares}") + + if prune_shares.size > 0 + machine.env.ui.warn("\n" + I18n.t("vagrant_sf_smb.uac.prune_warning") + "\n") + sleep UAC_PROMPT_WAIT + @@logger.info("remove shares: #{prune_shares}") + result = Vagrant::Util::PowerShell.execute(script_path, *prune_shares, sudo: true) + if result.exit_code != 0 + failed_name = result.stdout.to_s.sub("share name: ", "") + raise SyncedFolderSMB::Errors::PruneShareFailed, + name: failed_name, + stderr: result.stderr, + stdout: result.stdout + end + end + end + + def self.smb_prepare(env, machine, folders, opts) + script_path = File.expand_path("../../scripts/set_share.ps1", __FILE__) + + shares = [] + folders.each do |id, data| + hostpath = data[:hostpath] + + chksum_id = Digest::MD5.hexdigest(id) + name = "vgt-#{machine_id(machine)}-#{chksum_id}" + data[:smb_id] ||= name + + @@logger.info("creating new share name=#{name} id=#{data[:smb_id]}") + + shares << [ + "\"#{hostpath.gsub("/", "\\")}\"", + name, + data[:smb_id] + ] + end + if !shares.empty? + machine.env.ui.warn("\n" + I18n.t("vagrant_sf_smb.uac.create_warning") + "\n") + sleep(UAC_PROMPT_WAIT) + result = Vagrant::Util::PowerShell.execute(script_path, *shares, sudo: true) + if result.exit_code != 0 + share_path = result.stdout.to_s.sub("share path: ", "") + raise SyncedFolderSMB::Errors::DefineShareFailed, + host: share_path, + stderr: result.stderr, + stdout: result.stdout + end + end + end + + # Generates a unique identifier for the given machine + # based on the name, provider name, and working directory + # of the environment. + # + # @param [Vagrant::Machine] machine + # @return [String] + def self.machine_id(machine) + @@logger.debug("generating machine ID name=#{machine.name} cwd=#{machine.env.cwd}") + Digest::MD5.hexdigest("#{machine.name}-#{machine.provider_name}-#{machine.env.cwd}") + end + end + end + end +end diff --git a/plugins/hosts/windows/plugin.rb b/plugins/hosts/windows/plugin.rb index 84a38836b..38691d0a8 100644 --- a/plugins/hosts/windows/plugin.rb +++ b/plugins/hosts/windows/plugin.rb @@ -30,6 +30,26 @@ module VagrantPlugins require_relative "cap/ps" Cap::PS end + + host_capability("windows", "smb_installed") do + require_relative "cap/smb" + Cap::SMB + end + + host_capability("windows", "smb_prepare") do + require_relative "cap/smb" + Cap::SMB + end + + host_capability("windows", "smb_cleanup") do + require_relative "cap/smb" + Cap::SMB + end + + host_capability("windows", "configured_ip_addresses") do + require_relative "cap/configured_ip_addresses" + Cap::ConfiguredIPAddresses + end end end end diff --git a/plugins/synced_folders/smb/scripts/host_info.ps1 b/plugins/hosts/windows/scripts/host_info.ps1 similarity index 100% rename from plugins/synced_folders/smb/scripts/host_info.ps1 rename to plugins/hosts/windows/scripts/host_info.ps1 diff --git a/plugins/hosts/windows/scripts/set_share.ps1 b/plugins/hosts/windows/scripts/set_share.ps1 new file mode 100644 index 000000000..a102e08c2 --- /dev/null +++ b/plugins/hosts/windows/scripts/set_share.ps1 @@ -0,0 +1,39 @@ +# The names of the user are language dependent! +$objSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-1-0") +$objUser = $objSID.Translate([System.Security.Principal.NTAccount]) + +$grant = "$objUser,Full" + +# First we split the defs string by commas to get +# each group of parameters +for ($i=0; $i -le $args.length; $i = $i + 3) { + $path = $args[$i] + $share_name = $args[$i+1] + $share_id = $args[$i+2] + + + if ($path -eq $null) { + Write-Warning "empty path argument encountered - complete" + exit 0 + } + + if ($share_name -eq $null) { + Write-Output "share path: ${path}" + Write-Error "error - no share name provided" + exit 1 + } + + if ($share_id -eq $null) { + Write-Output "share path: ${path}" + Write-Error "error - no share ID provided" + exit 1 + } + + $result = net share $share_name=$path /unlimited /GRANT:$grant /REMARK:"${share_id}" + if ($LastExitCode -ne 0) { + $host.ui.WriteLine("share path: ${path}") + $host.ui.WriteErrorLine("error ${result}") + exit 1 + } +} +exit 0 diff --git a/plugins/hosts/windows/scripts/unset_share.ps1 b/plugins/hosts/windows/scripts/unset_share.ps1 new file mode 100644 index 000000000..ebbfda59b --- /dev/null +++ b/plugins/hosts/windows/scripts/unset_share.ps1 @@ -0,0 +1,11 @@ +# Share names are comma delimited +ForEach ($share_name in $args) { + $result = net share $share_name /DELETE + if ($LastExitCode -ne 0) { + Write-Output "share name: ${share_name}" + Write-Error "error - ${result}" + exit 1 + } +} +Write-Output "share removal completed" +exit 0 diff --git a/plugins/synced_folders/smb/errors.rb b/plugins/synced_folders/smb/errors.rb index 4a5d2503e..f660b46e5 100644 --- a/plugins/synced_folders/smb/errors.rb +++ b/plugins/synced_folders/smb/errors.rb @@ -10,6 +10,10 @@ module VagrantPlugins error_key(:define_share_failed) end + class PruneShareFailed < SMBError + error_key(:prune_share_failed) + end + class NoHostIPAddr < SMBError error_key(:no_routable_host_addr) end diff --git a/plugins/synced_folders/smb/scripts/set_share.ps1 b/plugins/synced_folders/smb/scripts/set_share.ps1 deleted file mode 100644 index 469483f38..000000000 --- a/plugins/synced_folders/smb/scripts/set_share.ps1 +++ /dev/null @@ -1,44 +0,0 @@ -Param( - [Parameter(Mandatory=$true)] - [string]$path, - [Parameter(Mandatory=$true)] - [string]$share_name, - [string]$host_share_username = $null -) - -$ErrorAction = "Stop" - -if (net share | Select-String $share_name) { - net share $share_name /delete /y -} - -# The names of the user are language dependent! -$objSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-1-0") -$objUser = $objSID.Translate([System.Security.Principal.NTAccount]) - -$grant = "$objUser,Full" - -if (![string]::IsNullOrEmpty($host_share_username)) { - $computer_name = $(Get-WmiObject Win32_Computersystem).name - $grant = "$computer_name\$host_share_username,Full" - - # Here we need to set the proper ACL for this folder. This lets full - # recursive access to this folder. - <# - Get-ChildItem $path -recurse -Force |% { - $current_acl = Get-ACL $_.fullname - $permission = "$computer_name\$host_share_username","FullControl","ContainerInherit,ObjectInherit","None","Allow" - $acl_access_rule = New-Object System.Security.AccessControl.FileSystemAccessRule $permission - $current_acl.SetAccessRule($acl_access_rule) - $current_acl | Set-Acl $_.fullname - } - #> -} - -$result = net share $share_name=$path /unlimited /GRANT:$grant -if ($LastExitCode -eq 0) { - exit 0 -} - -$host.ui.WriteErrorLine("Error: $result") -exit 1 diff --git a/plugins/synced_folders/smb/synced_folder.rb b/plugins/synced_folders/smb/synced_folder.rb index acdcc802e..dcbb903c6 100644 --- a/plugins/synced_folders/smb/synced_folder.rb +++ b/plugins/synced_folders/smb/synced_folder.rb @@ -17,69 +17,46 @@ module VagrantPlugins end def usable?(machine, raise_error=false) - if !Vagrant::Util::Platform.windows? - raise Errors::WindowsHostRequired if raise_error - return false - end - - if !Vagrant::Util::Platform.windows_admin? - raise Errors::WindowsAdminRequired if raise_error - return false - end - - psv = Vagrant::Util::PowerShell.version.to_i - if psv < 3 - if raise_error - raise Errors::PowershellVersion, - version: psv.to_s - end - return false - end - - true + # 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 Vagrant::Errors::SMBNotSupported end def prepare(machine, folders, opts) machine.ui.output(I18n.t("vagrant_sf_smb.preparing")) - script_path = File.expand_path("../scripts/set_share.ps1", __FILE__) + smb_username = smb_password = nil # If we need auth information, then ask the user. have_auth = false folders.each do |id, data| if data[:smb_username] && data[:smb_password] - @creds[:username] = data[:smb_username] - @creds[:password] = data[:smb_password] + smb_username = data[:smb_username] + smb_password = data[:smb_password] have_auth = true break end end if !have_auth - machine.ui.detail(I18n.t("vagrant_sf_smb.warning_password") + "\n ") - @creds[:username] = machine.ui.ask("Username: ") - @creds[:password] = machine.ui.ask("Password (will be hidden): ", echo: false) + machine.env.ui.detail(I18n.t("vagrant_sf_smb.warning_password") + "\n ") + smb_username = machine.env.ui.ask("Username: ") + smb_password = machine.env.ui.ask("Password (will be hidden): ", echo: false) end folders.each do |id, data| - hostpath = data[:hostpath] + data[:smb_username] ||= smb_username + data[:smb_password] ||= smb_password - data[:smb_id] ||= Digest::MD5.hexdigest( - "#{machine.id}-#{id.gsub("/", "-")}") - - args = [] - args << "-path" << "\"#{hostpath.gsub("/", "\\")}\"" - args << "-share_name" << data[:smb_id] - #args << "-host_share_username" << @creds[:username] - - r = Vagrant::Util::PowerShell.execute(script_path, *args) - if r.exit_code != 0 - raise Errors::DefineShareFailed, - host: hostpath.to_s, - stderr: r.stderr, - stdout: r.stdout - end + # Register password as sensitive + Vagrant::Util::CredentialScrubber.sensitive(smb_password) end + + machine.env.host.capability(:smb_prepare, machine, folders, opts) end def enable(machine, folders, nfsopts) @@ -109,7 +86,7 @@ module VagrantPlugins end if need_host_ip - candidate_ips = load_host_ips + 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) @@ -141,25 +118,8 @@ module VagrantPlugins end def cleanup(machine, opts) - - end - - protected - - def load_host_ips - script_path = File.expand_path("../scripts/host_info.ps1", __FILE__) - r = Vagrant::Util::PowerShell.execute(script_path) - if r.exit_code != 0 - raise Errors::PowershellError, - script: script_path, - stderr: r.stderr - end - - res = JSON.parse(r.stdout)["ip_addresses"] - if res.instance_of? String - [ res ] - else - res + if machine.env.host.capability?(:smb_cleanup) + machine.env.host.capability(:smb_cleanup, machine, opts) end end end diff --git a/templates/locales/synced_folder_smb.yml b/templates/locales/synced_folder_smb.yml index 442c99405..736640054 100644 --- a/templates/locales/synced_folder_smb.yml +++ b/templates/locales/synced_folder_smb.yml @@ -11,6 +11,13 @@ en: folders shortly. Please use the proper username/password of your Windows account. + uac: + prune_warning: |- + Vagrant requires administator access for pruning SMB shares and + may request access to complete removal of stale shares. + create_warning: |- + Vagrant requires administator access to create SMB shares and + may request access to complete setup of configured shares. errors: define_share_failed: |- Exporting an SMB share failed! Details about the failure are shown @@ -20,6 +27,15 @@ en: Stderr: %{stderr} + Stdout: %{stdout} + prune_share_failed: |- + Pruning an SMB share failed! Details about the failure are shown + below. Please inspect the error message and correct any problems. + + Share name: %{name} + + Stderr: %{stderr} + Stdout: %{stdout} no_routable_host_addr: |- We couldn't detect an IP address that was routable to this