Mitchell Hashimoto 1ef679f683 SSH log level fatal. Thanks @petejkim
This change makes it so that SSH errors are shown, whereas QUIET hid
those as well. The main change to QUIET was to get rid of warnings,
not errors, so this fixes that.
2012-05-31 23:42:28 +02:00

129 lines
4.7 KiB
Ruby

require 'log4r'
require 'vagrant/util/file_mode'
require 'vagrant/util/platform'
require 'vagrant/util/safe_exec'
module Vagrant
# Manages SSH connection information as well as allows opening an
# SSH connection.
class SSH
include Util::SafeExec
def initialize(vm)
@vm = vm
@logger = Log4r::Logger.new("vagrant::ssh")
end
# Returns a hash of information necessary for accessing this
# virtual machine via SSH.
#
# @return [Hash]
def info
results = {
:host => @vm.config.ssh.host,
:port => @vm.config.ssh.port || @vm.driver.ssh_port(@vm.config.ssh.guest_port),
:username => @vm.config.ssh.username,
:forward_agent => @vm.config.ssh.forward_agent,
:forward_x11 => @vm.config.ssh.forward_x11
}
# This can happen if no port is set and for some reason Vagrant
# can't detect an SSH port.
raise Errors::SSHPortNotDetected if !results[:port]
# Determine the private key path, which is either set by the
# configuration or uses just the built-in insecure key.
pk_path = @vm.config.ssh.private_key_path || @vm.env.default_private_key_path
results[:private_key_path] = File.expand_path(pk_path, @vm.env.root_path)
# We need to check and fix the private key permissions
# to make sure that SSH gets a key with 0600 perms.
check_key_permissions(results[:private_key_path])
# Return the results
return results
end
# Connects to the environment's virtual machine, replacing the ruby
# process with an SSH process.
#
# @param [Hash] opts Options hash
# @options opts [Boolean] :plain_mode If True, doesn't authenticate with
# the machine, only connects, allowing the user to connect.
def exec(opts={})
# Get the SSH information and cache it here
ssh_info = info
if Util::Platform.windows?
raise Errors::SSHUnavailableWindows, :host => ssh_info[:host],
:port => ssh_info[:port],
:username => ssh_info[:username],
:key_path => ssh_info[:private_key_path]
end
raise Errors::SSHUnavailable if !Kernel.system("which ssh > /dev/null 2>&1")
# If plain mode is enabled then we don't do any authentication (we don't
# set a user or an identity file)
plain_mode = opts[:plain_mode]
options = {}
options[:host] = ssh_info[:host]
options[:port] = ssh_info[:port]
options[:username] = ssh_info[:username]
options[:private_key_path] = ssh_info[:private_key_path]
# Command line options
command_options = ["-p", options[:port].to_s, "-o", "UserKnownHostsFile=/dev/null",
"-o", "StrictHostKeyChecking=no", "-o", "LogLevel=FATAL"]
# Solaris/OpenSolaris/Illumos uses SunSSH which doesn't support the IdentitiesOnly option
# (Also don't use it in plain mode, it'll skip user agents.)
command_options += ["-o", "IdentitiesOnly=yes"] if !(Util::Platform.solaris? || plain_mode)
command_options += ["-i", options[:private_key_path]] if !plain_mode
command_options += ["-o", "ForwardAgent=yes"] if ssh_info[:forward_agent]
# If there are extra options, then we append those
command_options.concat(opts[:extra_args]) if opts[:extra_args]
if ssh_info[:forward_x11]
# Both are required so that no warnings are shown regarding X11
command_options += ["-o", "ForwardX11=yes"]
command_options += ["-o", "ForwardX11Trusted=yes"]
end
host_string = options[:host]
host_string = "#{options[:username]}@#{host_string}" if !plain_mode
command_options << host_string
@logger.info("Invoking SSH: #{command_options.inspect}")
safe_exec("ssh", *command_options)
end
# Checks the file permissions for a private key, resetting them
# if needed.
def check_key_permissions(key_path)
# Windows systems don't have this issue
return if Util::Platform.windows?
@logger.debug("Checking key permissions: #{key_path}")
stat = File.stat(key_path)
if stat.owned? && Util::FileMode.from_octal(stat.mode) != "600"
@logger.info("Attempting to correct key permissions to 0600")
File.chmod(0600, key_path)
stat = File.stat(key_path)
if Util::FileMode.from_octal(stat.mode) != "600"
raise Errors::SSHKeyBadPermissions, :key_path => key_path
end
end
rescue Errno::EPERM
# This shouldn't happen since we verified we own the file, but
# it is possible in theory, so we raise an error.
raise Errors::SSHKeyBadPermissions, :key_path => key_path
end
end
end