Skip to content

Commit d2b2e00

Browse files
committed
elevate privileges in Windows host if necessary
1 parent 02758e3 commit d2b2e00

File tree

1 file changed

+50
-9
lines changed

1 file changed

+50
-9
lines changed

lib/vagrant-hostmanager/hosts_file.rb

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,23 @@ def update_guest(machine)
3434
def update_host
3535
# copy and modify hosts file on host with Vagrant-managed entries
3636
file = @global_env.tmp_path.join('hosts.local')
37-
# add a "if windows..."
38-
hosts_location = '/etc/hosts'
39-
copy_cmd = 'sudo cp'
40-
# handles the windows hosts file...
41-
if ENV['SystemRoot'] != nil
37+
38+
if WindowsSupport.windows?
39+
# lazily include windows Module
40+
class << self
41+
include WindowsSupport unless include? WindowsSupport
42+
end
43+
4244
hosts_location = "#{ENV['WINDIR']}\\System32\\drivers\\etc\\hosts"
43-
copy_cmd = 'cp'
45+
copy_proc = Proc.new { windows_copy_file(file, hosts_location) }
46+
else
47+
hosts_location = '/etc/hosts'
48+
copy_proc = Proc.new { `sudo cp #{file} #{hosts_location}` }
4449
end
50+
4551
FileUtils.cp(hosts_location, file)
4652
update_file(file)
47-
48-
# copy modified file using sudo for permission
49-
`#{copy_cmd} #{file} #{hosts_location}`
53+
copy_proc.call
5054
end
5155

5256
private
@@ -122,6 +126,43 @@ def get_machines
122126
@global_env.active_machines
123127
end
124128
end
129+
130+
## Windows support for copying files, requesting elevated privileges if necessary
131+
module WindowsSupport
132+
def self.windows?
133+
ENV['OS'] === 'Windows_NT'
134+
end
135+
136+
require 'win32ole' if windows?
137+
138+
def windows_copy_file(source, dest)
139+
begin
140+
# First, try Ruby copy
141+
FileUtils.cp(source, dest)
142+
rescue Errno::EACCES
143+
# Access denied, try with elevated privileges
144+
windows_copy_file_elevated(source, dest)
145+
end
146+
end
147+
148+
private
149+
150+
def windows_copy_file_elevated(source, dest)
151+
# copy command only supports backslashes as separators
152+
source, dest = [source, dest].map { |s| s.to_s.gsub(/\//, '\\') }
153+
154+
# run 'cmd /C copy ...' with elevated privilege, minimized
155+
copy_cmd = "copy \"#{source}\" \"#{dest}\""
156+
WIN32OLE.new('Shell.Application').ShellExecute('cmd', "/C #{copy_cmd}", nil, 'runas', 7)
157+
158+
# Unfortunately, ShellExecute does not give us a status code,
159+
# and it is non-blocking so we can't reliably compare the file contents
160+
# to see if they were copied.
161+
#
162+
# If the user rejects the UAC prompt, vagrant will silently continue
163+
# without updating the hostsfile.
164+
end
165+
end
125166
end
126167
end
127168
end

0 commit comments

Comments
 (0)