1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../lib"
require_relative '../common'
require 'mocha/minitest'
require 'pty'
require 'expect'
module IntegrationTestHelpers
VERBOSE = false
def sh(command)
puts "$ #{command}" if VERBOSE
res = system(command)
status = $?
raise "Command: #{command} failed:#{status.exitstatus}" unless res
end
def tmpdir(&block)
Dir.mktmpdir do |dir|
yield(dir)
end
end
def sshd_8_or_later?
!!(`sshd -v 2>&1 |grep 'OpenSSH_'` =~ /OpenSSH_8./)
end
def ssh_keygen(file, type = 'rsa', password = '')
sh "rm -rf #{file} #{file}.pub"
sh "ssh-keygen #{ssh_keygen_format} -q -f #{file} -t #{type} -N '#{password}'"
end
def ssh_keygen_format
if Net::SSH::Authentication::ED25519Loader::LOADED
""
else
"-m PEM"
end
end
def set_authorized_key(user, pubkey)
authorized_key = "/home/#{user}/.ssh/authorized_keys"
sh "sudo cp #{pubkey} #{authorized_key}"
sh "sudo chown #{user} #{authorized_key}"
sh "sudo chmod 0744 #{authorized_key}"
end
def sign_user_key(user, pubkey)
cert = "/etc/ssh/users_ca"
sh "sudo ssh-keygen -s #{cert} -I user_#{user} -n #{user} -V +52w #{pubkey}"
end
def with_agent(&block)
puts "/usr/bin/ssh-agent -c" if VERBOSE
agent_out = `/usr/bin/ssh-agent -c`
agent_out.split("\n").each do |line|
if line =~ /setenv (\S+) (\S+);/
ENV[$1] = $2
puts "ENV[#{$1}]=#{$2}" if VERBOSE
end
end
begin
yield
ensure
sh "/usr/bin/ssh-agent -k > /dev/null"
end
end
def ssh_add(key, password)
command = "ssh-add #{key}"
status = nil
PTY.spawn(command) do |reader, writer, pid|
begin
reader.expect(/Enter passphrase for .*:/) { |data| puts data }
writer.puts(password)
until reader.eof? do
line = reader.readline
puts line if VERBOSE
end
rescue Errno::EIO => _e
end
pid, status = Process.wait2 pid
end
raise "Command: #{command} failed:#{status.exitstatus}" unless status
status.exitstatus
end
def with_sshd_config(sshd_config, &block)
raise "Failed to copy config" unless system("sudo cp -f /etc/ssh/sshd_config /etc/ssh/sshd_config.original")
begin
Tempfile.open('sshd_config') do |f|
f.write(sshd_config)
f.close
system("sudo cp -f #{f.path} /etc/ssh/sshd_config")
end
system("sudo chmod 0644 /etc/ssh/sshd_config")
raise "Failed to restart sshd" unless system("sudo service ssh restart")
yield
ensure
system("sudo cp -f /etc/ssh/sshd_config.original /etc/ssh/sshd_config")
system("sudo service ssh restart")
end
end
def with_lines_as_tempfile(lines = [], add_pid: true, debug: false, &block)
Tempfile.open('sshd_config') do |f|
f.write(lines.join("\n"))
pidpath = nil
if add_pid
pidpath = f.path + '.pid'
f.write("\nPidFile #{pidpath}\n")
end
f.write("\nLogLevel DEBUG3\n") if debug
f.close
puts "CONFIG: #{f.path} PID: #{pidpath}" if debug
yield(f.path, pidpath)
end
end
def port_open?(path)
Socket.tcp("localhost", 10567, connect_timeout: 1) { true } rescue false # rubocop:disable Style/RescueModifier
end
# @yield [pid, port]
def start_sshd_7_or_later(port = '2200', config: nil, debug: false)
pid = nil
sshpidfile = nil
sshlogpath = nil
if config
with_lines_as_tempfile(config, debug: debug) do |path, pidpath|
puts "DEBUG - SSH LOG: #{path}-log.txt config: #{path}" if debug
raise "A leftover sshd is already running" if port_open?(port)
extra_params = []
sshlogpath = "#{path}-log.txt"
extra_params = ['-E', sshlogpath]
pid = spawn('sudo', '/opt/net-ssh-openssh/sbin/sshd', '-D', '-f', path, '-p', port, *extra_params)
sshpidfile = pidpath
yield pid, port
end
else
with_lines_as_tempfile(['']) do |path, pidpath|
pid = spawn('sudo', '/opt/net-ssh-openssh/sbin/sshd', '-D', '-f', path, '-p', port)
sshpidfile = pidpath
yield pid, port
end
end
ensure
# Our pid is sudo and not sshd, -9 (KILL) on sudo will not clean up its children
# properly, so we just have to hope that -15 (TERM) will manage to bring
# down sshd.
if sshpidfile
if !File.exist?(sshpidfile) && !sshlogpath.nil?
loglines = `sudo tail -n 10 #{sshlogpath}`.split("\n")
puts "ERROR: sshpidfile #{sshpidfile} does not exist\n\nSSH server logs:\n#{loglines.join("\n")}"
end
sshpid = File.read(sshpidfile).strip
system('sudo', 'kill', '-15', sshpid.to_s)
begin
Timeout.timeout(20) do
Process.wait(pid)
end
rescue Timeout::Error
warn "Failed to kill openssh process: #{sshpid}"
system('sudo', 'kill', '-9', sshpid.to_s)
raise
end
elsif pid
system('sudo', 'kill', '-15', pid.to_s)
begin
Timeout.timeout(20) do
Process.wait(pid)
end
rescue Timeout::Error
warn "Failed to kill openssh process: #{pid}"
system('sudo', 'kill', '-9', pid.to_s)
raise
end
end
end
def localhost
'localhost'
end
def user
'net_ssh_1'
end
end
|