diff --git a/CHANGES b/CHANGES index 09c076e67..b3f8bdd54 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,11 @@ Changelog +Yang Tse (3 Jan 2008) +- Modified test harness to allow SCP, SFTP and SOCKS4 tests to run with + OpenSSH 2.9.9, SunSSH 1.0 or later versions. SOCKS5 tests need OpenSSH + 3.7, SunSSH 1.0 or later. + Daniel S (2 Jan 2008) - I fixed two cases of missing return code checks when handling chunked decoding where a write error (or abort return from a callback) didn't stop diff --git a/TODO-RELEASE b/TODO-RELEASE index 297f46a6d..7d7e9fbbb 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -17,5 +17,8 @@ To be addressed before 7.18.0 (planned release: January 2008) auth (to find and fix) 114 - Ranged downloads on file:// URLs by Daniel Egger (patch failed to apply) + +115 - Cleanup debugging messages in test harness, introduced for new minimum + SSH version support for SCP, SFTP and SOCKS tests -115 - +116 - diff --git a/tests/Makefile.am b/tests/Makefile.am index 1bdbcdb7e..858e3a74d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2005, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -26,7 +26,7 @@ PDFPAGES = testcurl.pdf runtests.pdf EXTRA_DIST = ftpserver.pl httpserver.pl httpsserver.pl runtests.pl getpart.pm \ FILEFORMAT README stunnel.pem memanalyze.pl testcurl.pl valgrind.pm ftp.pm \ - sshserver.pl testcurl.1 runtests.1 $(HTMLPAGES) $(PDFPAGES) + sshserver.pl sshhelp.pm testcurl.1 runtests.1 $(HTMLPAGES) $(PDFPAGES) SUBDIRS = data server libtest diff --git a/tests/runtests.pl b/tests/runtests.pl index 9a7e14b9f..9cdcfe539 100755 --- a/tests/runtests.pl +++ b/tests/runtests.pl @@ -6,7 +6,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -63,6 +63,16 @@ use Cwd; @INC=(@INC, $ENV{'srcdir'}, "."); +# Variables and subs imported from sshhelp module +use sshhelp qw( + $sshexe + $sshconfig + $sshlog + display_sshlog + find_ssh + sshversioninfo + ); + require "getpart.pm"; # array functions require "valgrind.pm"; # valgrind report parser require "ftp.pm"; @@ -173,6 +183,11 @@ my %skipped; # skipped{reason}=counter, reasons for skip my @teststat; # teststat[testnum]=reason, reasons for skip my %disabled_keywords; # key words of tests to skip +my $sshid; # for socks server, ssh version id +my $sshvernum; # for socks server, ssh version number +my $sshverstr; # for socks server, ssh version string +my $ssherror; # for socks server, ssh version error + ####################################################################### # variables the command line options may set # @@ -294,7 +309,7 @@ sub startnew { die "error: exec() has returned"; } - # Ugly hack but ssh doesn't support pid files + # Ugly hack but ssh client doesn't support pid files if ($fake) { if(open(OUT, ">$pidfile")) { print OUT $child . "\n"; @@ -1042,6 +1057,7 @@ sub runsshserver { my ($id, $verbose, $ipv6) = @_; my $ip=$HOSTIP; my $port = $SSHPORT; + my $socksport = $SOCKSPORT; my $pidfile = $SSHPIDFILE; # don't retry if the server doesn't work @@ -1056,11 +1072,12 @@ sub runsshserver { stopserver($pid); } - my $flag=$debugprotocol?"-v ":""; - my $cmd="$perl $srcdir/sshserver.pl $flag-u $USER -l $HOSTIP -d $srcdir $port"; + my $flag=$verbose?'-v ':''; + $flag .= '-d ' if($debugprotocol); + + my $cmd="$perl $srcdir/sshserver.pl ${flag}-u $USER -l $ip -p $port -s $socksport"; logmsg "TRACESSH:runsshserver: calling startnew with cmd: $cmd\n"; - my ($sshpid, $pid2) = - startnew($cmd, $pidfile, 60, 0); # start the server in a new process + my ($sshpid, $pid2) = startnew($cmd, $pidfile, 60, 0); logmsg "TRACESSH:runsshserver: startnew returns sshpid: $sshpid pid2: $pid2\n"; @@ -1101,39 +1118,80 @@ sub runsocksserver { # don't retry if the server doesn't work if ($doesntrun{$pidfile}) { - logmsg "TRACESSH:runsocksserver: socks server previously failed to start with pidfile: $pidfile\n"; return (0,0); } - my $flag=$debugprotocol?"-v ":""; - my $cmd="ssh -D $SOCKSPORT -N -F curl_ssh_config ${USER}\@${HOSTIP} -p ${SSHPORT} -vv >log/ssh.log 2>&1"; - logmsg "TRACESSH:runsocksserver: calling startnew with cmd: $cmd\n"; - my ($sshpid, $pid2) = - startnew($cmd, $pidfile, 15, 1); # start the server in a new process + my $pid = checkserver($pidfile); + logmsg "TRACESSH:runsocksserver: checkserver on pidfile: $pidfile returns pid: $pid\n"; + if($pid > 0) { + stopserver($pid); + } + unlink($pidfile); + + # The ssh server must be already running + if(!$run{'ssh'}) { + logmsg "RUN: SOCKS server cannot find running SSH server\n"; + $doesntrun{$pidfile} = 1; + return (0,0); + } + + # Find out ssh client canonical file name + my $ssh = find_ssh(); + if(!$ssh) { + logmsg "RUN: SOCKS server cannot find $sshexe\n"; + $doesntrun{$pidfile} = 1; + return (0,0); + } + + # Find out ssh client version info + ($sshid, $sshvernum, $sshverstr, $ssherror) = sshversioninfo($ssh); + if(!$sshid) { + # Not an OpenSSH or SunSSH ssh client + logmsg "$ssherror\n" if($verbose); + logmsg "SCP, SFTP and SOCKS tests require OpenSSH 2.9.9 or later\n"; + $doesntrun{$pidfile} = 1; + return (0,0); + } + + # Verify minimum ssh client version + if((($sshid =~ /OpenSSH/) && ($sshvernum < 299)) || + (($sshid =~ /SunSSH/) && ($sshvernum < 100))) { + logmsg "ssh client found $ssh is $sshverstr\n"; + logmsg "SCP, SFTP and SOCKS tests require OpenSSH 2.9.9 or later\n"; + $doesntrun{$pidfile} = 1; + return (0,0); + } + logmsg "ssh client found $ssh is $sshverstr\n" if($verbose); + + # Config file options for ssh client are previously set from sshserver.pl + if(! -e $sshconfig) { + logmsg "RUN: SOCKS server cannot find $sshconfig\n"; + $doesntrun{$pidfile} = 1; + return (0,0); + } + + # start our socks server + my $cmd="$ssh -N -F $sshconfig $ip > $sshlog 2>&1"; + my ($sshpid, $pid2) = startnew($cmd, $pidfile, 30, 1); logmsg "TRACESSH:runsocksserver: startnew returns sshpid: $sshpid pid2: $pid2\n"; if($sshpid <= 0 || !kill(0, $sshpid)) { # it is NOT alive logmsg "RUN: failed to start the SOCKS server\n"; - logmsg "=== Start of file log/ssh.log\n"; - displaylogcontent("log/ssh.log"); - logmsg "=== End of file log/ssh.log\n"; - logmsg "TRACESSH:runsocksserver: calling stopserver with pid2: $pid2\n"; + display_sshlog(); stopserver("$pid2"); $doesntrun{$pidfile} = 1; - logmsg "TRACESSH:runsocksserver: later dont try to start a server with pidfile: $pidfile\n"; return (0,0); } # Ugly hack but ssh doesn't support pid files if (!verifyserver('socks',$ip,$port)) { logmsg "RUN: SOCKS server failed verification\n"; + display_sshlog(); # failed to talk to it properly. Kill the server and return failure - logmsg "TRACESSH:runsocksserver: calling stopserver with sshpid: $sshpid pid2: $pid2\n"; stopserver("$sshpid $pid2"); $doesntrun{$pidfile} = 1; - logmsg "TRACESSH:runsocksserver: later dont try to start a server with pidfile: $pidfile\n"; return (0,0); } if($verbose) { @@ -2404,36 +2462,34 @@ sub startservers { printf ("* pid ssh => %d %d\n", $pid, $pid2) if($verbose); $run{'ssh'}="$pid $pid2"; } - if ($what eq "socks4" || $what eq "socks5") { - if (!checkcmd("ssh")) { - return "failed to find SSH client for socks support"; - } - if(!$run{'socks'}) { - my $sshversion=`ssh -V 2>&1`; - if($sshversion =~ /OpenSSH[_-](\d+)\.(\d+)/i) { - if ($1*10+$2 < 36) { - # need 3.7 for socks5 - http://www.openssh.com/txt/release-3.7 - return "OpenSSH version ($1.$2) insufficient; need at least 3.7"; - } - } - elsif($sshversion =~ /Sun[_-]SSH[_-](\d+)\.(\d+)/i) { - if ($1*10+$2 < 11) { - return "SunSSH version ($1.$2) insufficient; need at least 1.1"; - } - } - else { - return "Unsupported ssh client\n"; - } - - ($pid, $pid2) = runsocksserver("", $verbose); + if($what eq "socks4" || $what eq "socks5") { + if(!$run{'socks'}) { + ($pid, $pid2) = runsocksserver("", 1); printf ("TRACESSH:startservers: runsocksserver returns pid: %d pid2: %d\n", $pid, $pid2); if($pid <= 0) { return "failed starting socks server"; } printf ("* pid socks => %d %d\n", $pid, $pid2) if($verbose); $run{'socks'}="$pid $pid2"; - } - } + } + } + if($what eq "socks5") { + if(!$sshid) { + # Not an OpenSSH or SunSSH ssh client + logmsg "Not OpenSSH or SunSSH; socks5 tests need at least OpenSSH 3.7\n"; + return "failed starting socks5 server"; + } + elsif(($sshid =~ /OpenSSH/) && ($sshvernum < 370)) { + # Need OpenSSH 3.7 for socks5 - http://www.openssh.com/txt/release-3.7 + logmsg "$sshverstr insufficient; socks5 tests need at least OpenSSH 3.7\n"; + return "failed starting socks5 server"; + } + elsif(($sshid =~ /SunSSH/) && ($sshvernum < 100)) { + # Need SunSSH 1.0 for socks5 + logmsg "$sshverstr insufficient; socks5 tests need at least SunSSH 1.0\n"; + return "failed starting socks5 server"; + } + } } elsif($what eq "none") { logmsg "* starts no server\n" if ($verbose); @@ -2881,6 +2937,8 @@ close(CMDLOG); # Tests done, stop the servers stopservers($verbose); +unlink($SOCKSPIDFILE); + my $all = $total + $skipped; if($total) { diff --git a/tests/sshhelp.pm b/tests/sshhelp.pm new file mode 100644 index 000000000..efe7a7f32 --- /dev/null +++ b/tests/sshhelp.pm @@ -0,0 +1,344 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +# $Id: +#*************************************************************************** + +package sshhelp; + +use strict; +#use warnings; +use Exporter; +use File::Spec; + + +#*************************************************************************** +# Global symbols allowed without explicit package name +# +use vars qw( + @ISA + @EXPORT_OK + $sshdexe + $sshexe + $sftpexe + $sshkeygenexe + $sshdconfig + $sshconfig + $knownhosts + $sshdlog + $sshlog + $hstprvkeyf + $hstpubkeyf + $cliprvkeyf + $clipubkeyf + @sftppath + ); + + +#*************************************************************************** +# Inherit Exporter's capabilities +# +@ISA = qw(Exporter); + + +#*************************************************************************** +# Global symbols this module will export upon request +# +@EXPORT_OK = qw( + $sshdexe + $sshexe + $sftpexe + $sshkeygenexe + $sshdconfig + $sshconfig + $knownhosts + $sshdlog + $sshlog + $hstprvkeyf + $hstpubkeyf + $cliprvkeyf + $clipubkeyf + display_sshdconfig + display_sshconfig + display_sshdlog + display_sshlog + dump_array + find_sshd + find_ssh + find_sftp + find_sshkeygen + logmsg + sshversioninfo + ); + + +#*************************************************************************** +# Global variables initialization +# +$sshdexe = 'sshd' .exe_ext(); # base name and ext of ssh daemon +$sshexe = 'ssh' .exe_ext(); # base name and ext of ssh client +$sftpexe = 'sftp-server' .exe_ext(); # base name and ext of sftp-server +$sshkeygenexe = 'ssh-keygen' .exe_ext(); # base name and ext of ssh-keygen +$sshdconfig = 'curl_sshd_config'; # ssh daemon config file +$sshconfig = 'curl_ssh_config'; # ssh client config file +$sshdlog = 'log/sshd.log'; # ssh daemon log file +$sshlog = 'log/ssh.log'; # ssh client log file +$knownhosts = 'curl_client_knownhosts'; # ssh knownhosts file +$hstprvkeyf = 'curl_host_dsa_key'; # host private key file +$hstpubkeyf = 'curl_host_dsa_key.pub'; # host public key file +$cliprvkeyf = 'curl_client_key'; # client private key file +$clipubkeyf = 'curl_client_key.pub'; # client public key file + + +#*************************************************************************** +# Absolute paths where to look for sftp-server plugin +# +@sftppath = qw( + /usr/lib/openssh + /usr/libexec/openssh + /usr/libexec + /usr/local/libexec + /opt/local/libexec + /usr/lib/ssh + /usr/libexec/ssh + /usr/sbin + /usr/lib + /usr/lib/ssh/openssh + /usr/lib64/ssh + /usr/lib64/misc + /usr/lib/misc + /usr/local/sbin + /usr/freeware/bin + /opt/ssh/sbin + /opt/ssh/libexec + ); + + +#*************************************************************************** +# Return file extension for executable files on this operating system +# +sub exe_ext { + if ($^O eq 'MSWin32' || $^O eq 'cygwin' || $^O eq 'msys' || + $^O eq 'dos' || $^O eq 'os2') { + return '.exe'; + } +} + + +#*************************************************************************** +# Create or overwrite the given file with lines from an array of strings +# +sub dump_array { + my ($filename, @arr) = @_; + my $error; + + if(!$filename) { + $error = 'Error: Missing argument 1 for dump_array()'; + } + elsif(open(TEXTFH, ">$filename")) { + foreach my $line (@arr) { + $line .= "\n" unless($line =~ /\n$/); + print TEXTFH $line; + } + if(!close(TEXTFH)) { + $error = "Error: cannot close file $filename"; + } + } + else { + $error = "Error: cannot write file $filename"; + } + return $error; +} + + +#*************************************************************************** +# Display a message +# +sub logmsg { + my ($line) = @_; + chomp $line if($line); + $line .= "\n"; + print "$line"; +} + + +#*************************************************************************** +# Display contents of the given file +# +sub display_file { + my $filename = $_[0]; + print "=== Start of file $filename\n"; + if(open(DISPLAYFH, "<$filename")) { + while(my $line = ) { + print "$line"; + } + close DISPLAYFH; + } + print "=== End of file $filename\n"; +} + + +#*************************************************************************** +# Display contents of the ssh daemon config file +# +sub display_sshdconfig { + display_file($sshdconfig); +} + + +#*************************************************************************** +# Display contents of the ssh client config file +# +sub display_sshconfig { + display_file($sshconfig); +} + + +#*************************************************************************** +# Display contents of the ssh daemon log file +# +sub display_sshdlog { + display_file($sshdlog); +} + + +#*************************************************************************** +# Display contents of the ssh client log file +# +sub display_sshlog { + display_file($sshlog); +} + + +#*************************************************************************** +# Find a file somewhere in the given path +# +sub find_file { + my $fn = $_[0]; + shift; + my @path = @_; + foreach (@path) { + my $file = File::Spec->catfile($_, $fn); + if(-e $file) { + return $file; + } + } +} + + +#*************************************************************************** +# Find a file in environment path or in our sftppath +# +sub find_sfile { + my $filename = $_[0]; + my @spath; + push(@spath, File::Spec->path()); + push(@spath, @sftppath); + return find_file($filename, @spath); +} + + +#*************************************************************************** +# Find ssh daemon and return canonical filename +# +sub find_sshd { + return find_sfile($sshdexe); +} + + +#*************************************************************************** +# Find ssh client and return canonical filename +# +sub find_ssh { + return find_sfile($sshexe); +} + + +#*************************************************************************** +# Find sftp-server plugin and return canonical filename +# +sub find_sftp { + return find_sfile($sftpexe); +} + + +#*************************************************************************** +# Find ssh-keygen and return canonical filename +# +sub find_sshkeygen { + return find_sfile($sshkeygenexe); +} + + +#*************************************************************************** +# Return version info for the given ssh client or server binaries +# +sub sshversioninfo { + my $sshbin = $_[0]; # canonical filename + my $major; + my $minor; + my $patch; + my $sshid; + my $versnum; + my $versstr; + my $error; + + if(!$sshbin) { + $error = 'Error: Missing argument 1 for sshversioninfo()'; + } + elsif(! -x $sshbin) { + $error = "Error: cannot read or execute $sshbin"; + } + else { + my $cmd = ($sshbin =~ /$sshdexe$/) ? "$sshbin -?" : "$sshbin -V"; + $error = "$cmd\n"; + foreach my $tmpstr (qx($cmd 2>&1)) { + if($tmpstr =~ /OpenSSH[_-](\d+)\.(\d+)(\.(\d+))*/i) { + $major = $1; + $minor = $2; + $patch = $4?$4:0; + $sshid = 'OpenSSH'; + $versnum = (100*$major) + (10*$minor) + $patch; + $versstr = "$sshid $major.$minor.$patch"; + $error = undef; + last; + } + if($tmpstr =~ /Sun[_-]SSH[_-](\d+)\.(\d+)(\.(\d+))*/i) { + $major = $1; + $minor = $2; + $patch = $4?$4:0; + $sshid = 'SunSSH'; + $versnum = (100*$major) + (10*$minor) + $patch; + $versstr = "$sshid $major.$minor.$patch"; + $error = undef; + last; + } + $error .= $tmpstr; + } + chomp $error if($error); + } + return ($sshid, $versnum, $versstr, $error); +} + + +#*************************************************************************** +# End of library +1; + diff --git a/tests/sshserver.pl b/tests/sshserver.pl index dafa60e24..2d95ea3ee 100644 --- a/tests/sshserver.pl +++ b/tests/sshserver.pl @@ -1,344 +1,856 @@ -#/usr/bin/env perl +#!/usr/bin/env perl +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# # $Id$ +#*************************************************************************** + # Starts sshd for use in the SCP, SFTP and SOCKS curl test harness tests. -# Also creates the ssh configuration files (this could be moved to a -# separate script). +# Also creates the ssh configuration files needed for these tests. # Options: -# -u user +# # -v -# target_port +# -d +# -u user +# -l listen address +# -p SCP/SFTP server port +# -s SOCKS4/5 server port use strict; -use File::Spec; +#use warnings; use Cwd; -my $verbose=1; # set to 1 for debugging -my $showfiles=0; - -my $port = 8999; # just our default, weird enough -my $listenaddr = "127.0.0.1"; # address on which to listen - -my $conffile="curl_sshd_config"; # sshd configuration data -my $conffile_ssh="curl_ssh_config"; # ssh configuration data -my $knownhostsfile="curl_client_knownhosts"; # ssh knownhosts file - -my $path = getcwd(); - -my $exeext; -if ($^O eq 'MSWin32' || $^O eq 'cygwin' || $^O eq 'msys' || $^O eq 'dos' || $^O eq 'os2') { - $exeext = '.exe'; -} - -# Where to look for sftp-server -my @sftppath = qw( - /usr/lib/openssh - /usr/libexec/openssh - /usr/libexec - /usr/local/libexec - /opt/local/libexec - /usr/lib/ssh - /usr/libexec/ssh - /usr/sbin - /usr/lib - /usr/lib/ssh/openssh - /usr/lib64/ssh - /usr/lib64/misc - /usr/lib/misc - /usr/local/sbin - /usr/freeware/bin - /opt/ssh/sbin - /opt/ssh/libexec +#*************************************************************************** +# Variables and subs imported from sshhelp module +# +use sshhelp qw( + $sshdexe + $sshexe + $sftpexe + $sshkeygenexe + $sshdconfig + $sshconfig + $knownhosts + $sshdlog + $sshlog + $hstprvkeyf + $hstpubkeyf + $cliprvkeyf + $clipubkeyf + display_sshdconfig + display_sshconfig + display_sshdlog + display_sshlog + dump_array + find_sshd + find_ssh + find_sftp + find_sshkeygen + logmsg + sshversioninfo ); -my $username = $ENV{USER}; +#*************************************************************************** -# Find a file somewhere in the given path -sub searchpath { - my $fn = $_[0] . $exeext; - shift; - my @path = @_; - foreach (@path) { - my $file = File::Spec->catfile($_, $fn); - if (-e $file) { - return $file; - } - } -} +my $verbose = 1; # set to 1 for debugging +my $debugprotocol = 0; # set to 1 for protocol debugging +my $port = 8999; # our default SCP/SFTP server port +my $socksport = $port + 1; # our default SOCKS4/5 server port +my $listenaddr = '127.0.0.1'; # default address on which to listen +my $path = getcwd(); # current working directory +my $username = $ENV{USER}; # default user -# Display contents of the given file. -sub displayfile { - my ($file) = @_; - print "=== Start of file $file\n"; - if(open(SINGLE, "<$file")) { - while(my $string = ) { - print "$string"; - } - close(SINGLE); +my $error; +my @cfgarr; + + +#*************************************************************************** +# Parse command line options +# +while(@ARGV) { + if($ARGV[0] eq '-v') { + $verbose = 1; } - print "=== End of file $file\n"; -} - -# Append a string to sshd config file -sub set_sshd_option { - my ($string) = @_; - if (open(FILE, ">>$conffile")) { - print FILE "$string\n"; - close FILE; + elsif($ARGV[0] eq '-d') { + $verbose = 1; + $debugprotocol = 1; } -} - -# Append a string to ssh config file -sub set_ssh_option { - my ($string) = @_; - if (open(FILE, ">>$conffile_ssh")) { - print FILE "$string\n"; - close FILE; - } -} - -# Parse options -do { - if($ARGV[0] eq "-v") { - $verbose=1; - } - elsif($ARGV[0] eq "-u") { - $username=$ARGV[1]; + elsif($ARGV[0] eq '-u') { + $username = $ARGV[1]; shift @ARGV; } - elsif($ARGV[0] eq "-l") { - $listenaddr=$ARGV[1]; + elsif($ARGV[0] eq '-l') { + $listenaddr = $ARGV[1]; shift @ARGV; } - elsif($ARGV[0] =~ /^(\d+)$/) { - $port = $1; - } -} while(shift @ARGV); - -# Searching for sshd and sftp-server will be done first -# in the PATH and afterwards in other common locations. -my @spath; -push(@spath, File::Spec->path()); -push(@spath, @sftppath); - -# sshd insists on being called with an absolute path. -my $sshd = searchpath("sshd", @spath); -if (!$sshd) { - print "sshd$exeext not found\n"; - exit 1; -} -if ($verbose) { - print "SSH server found is $sshd\n"; -} - -my $sftp = searchpath("sftp-server", @spath); -if (!$sftp) { - print "Could not find sftp-server$exeext plugin\n"; - exit 1; -} -if ($verbose) { - print "SFTP server plugin found is $sftp\n"; -} - -if ($username eq "root") { - print "Will not run ssh daemon as root to mitigate security risks\n"; - exit 1; -} - -# Find out sshd version. -my $tmpstr; -my $ssh_daemon; -my $ssh_ver_major; -my $ssh_ver_minor; -my $ssh_ver_patch; -my $ssh_version; -foreach $tmpstr (qx($sshd -V 2>&1)) { - if($tmpstr =~ /OpenSSH[_-](\d+)\.(\d+)(\.(\d+))*/i) { - ($ssh_ver_major, $ssh_ver_minor, $ssh_ver_patch) = ($1, $2, $4); - $ssh_daemon = 'OpenSSH'; - $ssh_version = 10 * $ssh_ver_major + $ssh_ver_minor; - if($ssh_version == 36) { - $showfiles=1; + elsif($ARGV[0] eq '-p') { + if($ARGV[1] =~ /^(\d+)$/) { + $port = $1; } - last; + shift @ARGV; } - if($tmpstr =~ /Sun[_-]SSH[_-](\d+)\.(\d+)/i) { - ($ssh_ver_major, $ssh_ver_minor) = ($1, $2); - $ssh_daemon = 'SunSSH'; - $ssh_version = 10 * $ssh_ver_major + $ssh_ver_minor; - if($ssh_version == 11) { - $showfiles=1; + elsif($ARGV[0] eq '-s') { + if($ARGV[1] =~ /^(\d+)$/) { + $socksport = $1; } - last; + shift @ARGV; } -} + shift @ARGV; +}; -# Verify minimum SSH daemon version. -my $sshd_ver_ok = 1; -if(!$ssh_daemon) { - if($verbose) { - print "unsupported SSH server daemon found\n"; - chomp($tmpstr = qx($sshd -V 2>&1)); - print "$tmpstr\n"; - } - $sshd_ver_ok = 0; + +#*************************************************************************** +# Logging level for ssh server and client +# +my $loglevel = $debugprotocol?'DEBUG2':'INFO'; + + +#*************************************************************************** +# Validate username +# +if(!$username) { + $error = 'Will not run ssh server without a user name'; } -elsif(($ssh_daemon =~ /OpenSSH/) && ($ssh_version < 36)) { - if($verbose) { - print "sshd found is $ssh_daemon $ssh_ver_major.$ssh_ver_minor\n"; - } - $sshd_ver_ok = 0; +elsif($username eq 'root') { + $error = 'Will not run ssh server as root to mitigate security risks'; } -elsif(($ssh_daemon =~ /SunSSH/) && ($ssh_version < 11)) { - if($verbose) { - print "sshd found is $ssh_daemon $ssh_ver_major.$ssh_ver_minor\n"; - } - $sshd_ver_ok = 0; -} -if(!$sshd_ver_ok) { - print "SCP, SFTP and SOCKS tests require OpenSSH 3.7 or later\n"; +if($error) { + logmsg $error; exit 1; } -# Initialize sshd configuration file for curl's tests. -open(CONF, ">$conffile") || die "Could not write $conffile"; -print CONF "# This is a generated file! Do not edit!\n"; -print CONF "# $ssh_daemon $ssh_ver_major.$ssh_ver_minor sshd configuration file for curl testing\n"; -close CONF; -# Support for some options might have not been built into sshd. On some -# platforms specifying an unsupported option prevents sshd from starting. -# Check here for possible unsupported options, avoiding its use in sshd. -sub sshd_supports_opt($) { - my ($option) = @_; - my $err = grep /((Unsupported)|(Bad configuration)|(Deprecated)) option.*$option/, - qx($sshd -t -f $conffile -o $option=no 2>&1); - return !$err; +#*************************************************************************** +# Find out ssh daemon canonical file name +# +my $sshd = find_sshd(); +if(!$sshd) { + logmsg "cannot find $sshdexe"; + exit 1; } -my $supports_UsePAM = sshd_supports_opt('UsePAM'); -my $supports_UseDNS = sshd_supports_opt('UseDNS'); -my $supports_ChReAu = sshd_supports_opt('ChallengeResponseAuthentication'); -if (! -e "curl_client_key.pub") { - if ($verbose) { - print "Generating host and client keys...\n"; - } +#*************************************************************************** +# Find out ssh daemon version info +# +my ($sshdid, $sshdvernum, $sshdverstr, $sshderror) = sshversioninfo($sshd); +if(!$sshdid) { + # Not an OpenSSH or SunSSH ssh daemon + logmsg $sshderror if($verbose); + logmsg 'SCP, SFTP and SOCKS tests require OpenSSH 2.9.9 or later'; + exit 1; +} +logmsg "ssh server found $sshd is $sshdverstr" if($verbose); + + +#*************************************************************************** +# ssh daemon command line options we might use and version support +# +# -e: log stderr : OpenSSH 2.9.0 and later +# -f: sshd config file : OpenSSH 1.2.1 and later +# -D: no daemon forking : OpenSSH 2.5.0 and later +# -o: command-line option : OpenSSH 3.1.0 and later +# -t: test config file : OpenSSH 2.9.9 and later +# -?: sshd version info : OpenSSH 1.2.1 and later +# +# -e: log stderr : SunSSH 1.0.0 and later +# -f: sshd config file : SunSSH 1.0.0 and later +# -D: no daemon forking : SunSSH 1.0.0 and later +# -o: command-line option : SunSSH 1.0.0 and later +# -t: test config file : SunSSH 1.0.0 and later +# -?: sshd version info : SunSSH 1.0.0 and later + + +#*************************************************************************** +# Verify minimum ssh daemon version +# +if((($sshdid =~ /OpenSSH/) && ($sshdvernum < 299)) || + (($sshdid =~ /SunSSH/) && ($sshdvernum < 100))) { + logmsg 'SCP, SFTP and SOCKS tests require OpenSSH 2.9.9 or later'; + exit 1; +} + + +#*************************************************************************** +# Find out sftp server plugin canonical file name +# +my $sftp = find_sftp(); +if(!$sftp) { + logmsg "cannot find $sftpexe"; + exit 1; +} +logmsg "sftp server plugin found $sftp" if($verbose); + + +#*************************************************************************** +# Find out ssh keygen canonical file name +# +my $sshkeygen = find_sshkeygen(); +if(!$sshkeygen) { + logmsg "cannot find $sshkeygenexe"; + exit 1; +} +logmsg "ssh keygen found $sshkeygen" if($verbose); + + +#*************************************************************************** +# Find out ssh client canonical file name +# +my $ssh = find_ssh(); +if(!$ssh) { + logmsg "cannot find $sshexe"; + exit 1; +} + + +#*************************************************************************** +# Find out ssh client version info +# +my ($sshid, $sshvernum, $sshverstr, $ssherror) = sshversioninfo($ssh); +if(!$sshid) { + # Not an OpenSSH or SunSSH ssh client + logmsg $ssherror if($verbose); + logmsg 'SCP, SFTP and SOCKS tests require OpenSSH 2.9.9 or later'; + exit 1; +} +logmsg "ssh client found $ssh is $sshverstr" if($verbose); + + +#*************************************************************************** +# ssh client command line options we might use and version support +# +# -D: dynamic app port forwarding : OpenSSH 2.9.9 and later +# -F: ssh config file : OpenSSH 2.9.9 and later +# -N: no shell/command : OpenSSH 2.1.0 and later +# -p: connection port : OpenSSH 1.2.1 and later +# -v: verbose messages : OpenSSH 1.2.1 and later +# -vv: increase verbosity : OpenSSH 2.3.0 and later +# -V: ssh version info : OpenSSH 1.2.1 and later +# +# -D: dynamic app port forwarding : SunSSH 1.0.0 and later +# -F: ssh config file : SunSSH 1.0.0 and later +# -N: no shell/command : SunSSH 1.0.0 and later +# -p: connection port : SunSSH 1.0.0 and later +# -v: verbose messages : SunSSH 1.0.0 and later +# -vv: increase verbosity : SunSSH 1.0.0 and later +# -V: ssh version info : SunSSH 1.0.0 and later + + +#*************************************************************************** +# Verify minimum ssh client version +# +if((($sshid =~ /OpenSSH/) && ($sshvernum < 299)) || + (($sshid =~ /SunSSH/) && ($sshvernum < 100))) { + logmsg 'SCP, SFTP and SOCKS tests require OpenSSH 2.9.9 or later'; + exit 1; +} + + +#*************************************************************************** +# ssh keygen command line options we actually use and version support +# +# -C: identity comment : OpenSSH 1.2.1 and later +# -f: key filename : OpenSSH 1.2.1 and later +# -N: new passphrase : OpenSSH 1.2.1 and later +# -q: quiet keygen : OpenSSH 1.2.1 and later +# -t: key type : OpenSSH 2.5.0 and later +# +# -C: identity comment : SunSSH 1.0.0 and later +# -f: key filename : SunSSH 1.0.0 and later +# -N: new passphrase : SunSSH 1.0.0 and later +# -q: quiet keygen : SunSSH 1.0.0 and later +# -t: key type : SunSSH 1.0.0 and later + + +#*************************************************************************** +# Generate host and client key files for curl's tests +# +if((! -e $hstprvkeyf) || (! -e $hstpubkeyf) || + (! -e $cliprvkeyf) || (! -e $clipubkeyf)) { # Make sure all files are gone so ssh-keygen doesn't complain - unlink("curl_host_dsa_key", "curl_client_key","curl_host_dsa_key.pub", "curl_client_key.pub"); - system "ssh-keygen -q -t dsa -f curl_host_dsa_key -C 'curl test server' -N ''" and die "Could not generate host key"; - system "ssh-keygen -q -t dsa -f curl_client_key -C 'curl test client' -N ''" and die "Could not generate client key"; -} - -open(FILE, ">>$conffile") || die "Could not write $conffile"; -print FILE < }; -close DSAKEYFILE || die "Could not close DSAKEYFILE"; - -open(KNOWNHOSTS, ">$knownhostsfile") || die "Could not write $knownhostsfile"; -print KNOWNHOSTS "[$listenaddr]:$port ssh-dss $dsahostkey[1]\n" || die 'Could not write to KNOWNHOSTS'; -close KNOWNHOSTS || die "Could not close KNOWNHOSTS"; - -open(SSHFILE, ">$conffile_ssh") || die "Could not write $conffile_ssh"; -print SSHFILE <= 37)) { - set_ssh_option('ConnectTimeout 20'); # Supported in OpenSSH 3.7 and later -} +#*************************************************************************** +# ssh daemon configuration file options we might use and version support +# +# AFSTokenPassing : OpenSSH 1.2.1 and later [1] +# AcceptEnv : OpenSSH 3.9.0 and later +# AddressFamily : OpenSSH 4.0.0 and later +# AllowGroups : OpenSSH 1.2.1 and later +# AllowTcpForwarding : OpenSSH 2.3.0 and later +# AllowUsers : OpenSSH 1.2.1 and later +# AuthorizedKeysFile : OpenSSH 2.9.9 and later +# Banner : OpenSSH 2.5.0 and later +# ChallengeResponseAuthentication : OpenSSH 2.5.0 and later +# Ciphers : OpenSSH 2.1.0 and later [3] +# ClientAliveCountMax : OpenSSH 2.9.0 and later +# ClientAliveInterval : OpenSSH 2.9.0 and later +# Compression : OpenSSH 3.3.0 and later +# DenyGroups : OpenSSH 1.2.1 and later +# DenyUsers : OpenSSH 1.2.1 and later +# ForceCommand : OpenSSH 4.4.0 and later [3] +# GatewayPorts : OpenSSH 2.1.0 and later +# GSSAPIAuthentication : OpenSSH 3.7.0 and later [1] +# GSSAPICleanupCredentials : OpenSSH 3.8.0 and later [1] +# HostbasedAuthentication : OpenSSH 2.9.0 and later +# HostbasedUsesNameFromPacketOnly : OpenSSH 2.9.0 and later +# HostKey : OpenSSH 1.2.1 and later +# IgnoreRhosts : OpenSSH 1.2.1 and later +# IgnoreUserKnownHosts : OpenSSH 1.2.1 and later +# KeepAlive : OpenSSH 1.2.1 and later +# KerberosAuthentication : OpenSSH 1.2.1 and later [1] +# KerberosGetAFSToken : OpenSSH 3.8.0 and later [1] +# KerberosOrLocalPasswd : OpenSSH 1.2.1 and later [1] +# KerberosTgtPassing : OpenSSH 1.2.1 and later [1] +# KerberosTicketCleanup : OpenSSH 1.2.1 and later [1] +# KeyRegenerationInterval : OpenSSH 1.2.1 and later +# ListenAddress : OpenSSH 1.2.1 and later +# LoginGraceTime : OpenSSH 1.2.1 and later +# LogLevel : OpenSSH 1.2.1 and later +# MACs : OpenSSH 2.5.0 and later [3] +# Match : OpenSSH 4.4.0 and later [3] +# MaxAuthTries : OpenSSH 3.9.0 and later +# MaxStartups : OpenSSH 2.2.0 and later +# PasswordAuthentication : OpenSSH 1.2.1 and later +# PermitEmptyPasswords : OpenSSH 1.2.1 and later +# PermitOpen : OpenSSH 4.4.0 and later [3] +# PermitRootLogin : OpenSSH 1.2.1 and later +# PermitTunnel : OpenSSH 4.3.0 and later +# PermitUserEnvironment : OpenSSH 3.5.0 and later +# PidFile : OpenSSH 2.1.0 and later +# Port : OpenSSH 1.2.1 and later +# PrintLastLog : OpenSSH 2.9.0 and later +# PrintMotd : OpenSSH 1.2.1 and later +# Protocol : OpenSSH 2.1.0 and later +# PubkeyAuthentication : OpenSSH 2.5.0 and later +# RhostsRSAAuthentication : OpenSSH 1.2.1 and later +# RSAAuthentication : OpenSSH 1.2.1 and later +# ServerKeyBits : OpenSSH 1.2.1 and later +# SkeyAuthentication : OpenSSH 1.2.1 and later [1] +# StrictModes : OpenSSH 1.2.1 and later +# Subsystem : OpenSSH 2.2.0 and later +# SyslogFacility : OpenSSH 1.2.1 and later +# TCPKeepAlive : OpenSSH 3.8.0 and later +# UseDNS : OpenSSH 3.7.0 and later +# UseLogin : OpenSSH 1.2.1 and later +# UsePAM : OpenSSH 3.7.0 and later [1][2] +# UsePrivilegeSeparation : OpenSSH 3.2.2 and later +# X11DisplayOffset : OpenSSH 1.2.1 and later [3] +# X11Forwarding : OpenSSH 1.2.1 and later +# X11UseLocalhost : OpenSSH 3.1.0 and later +# XAuthLocation : OpenSSH 2.1.1 and later [3] +# +# [1] Option only available if activated at compile time +# [2] Option specific for portable versions +# [3] Option not used in our ssh server config file -# Verify that sshd supports our configuration file -if (system "$sshd -t -f $conffile > log/sshd.log 2>&1") { - print "sshd configuration file failed verification\n"; - displayfile("log/sshd.log"); - displayfile("$conffile"); - unlink "log/sshd.log"; - unlink $conffile; +#*************************************************************************** +# Initialize sshd config with options actually supported in OpenSSH 2.9.9 +# +logmsg 'generating ssh server config file...' if($verbose); +@cfgarr = (); +push @cfgarr, '# This is a generated file. Do not edit.'; +push @cfgarr, "# $sshdverstr sshd configuration file for curl testing"; +push @cfgarr, '#'; +push @cfgarr, "DenyUsers !$username"; +push @cfgarr, "AllowUsers $username"; +push @cfgarr, 'DenyGroups'; +push @cfgarr, 'AllowGroups'; +push @cfgarr, '#'; +push @cfgarr, "AuthorizedKeysFile $path/$clipubkeyf"; +push @cfgarr, "HostKey $path/$hstprvkeyf"; +push @cfgarr, "PidFile $path/.ssh.pid"; +push @cfgarr, '#'; +push @cfgarr, "Port $port"; +push @cfgarr, "ListenAddress $listenaddr"; +push @cfgarr, 'Protocol 2'; +push @cfgarr, '#'; +push @cfgarr, 'AllowTcpForwarding yes'; +push @cfgarr, 'Banner none'; +push @cfgarr, 'ChallengeResponseAuthentication no'; +push @cfgarr, 'ClientAliveCountMax 3'; +push @cfgarr, 'ClientAliveInterval 0'; +push @cfgarr, 'GatewayPorts no'; +push @cfgarr, 'HostbasedAuthentication no'; +push @cfgarr, 'HostbasedUsesNameFromPacketOnly no'; +push @cfgarr, 'IgnoreRhosts yes'; +push @cfgarr, 'IgnoreUserKnownHosts yes'; +push @cfgarr, 'KeyRegenerationInterval 0'; +push @cfgarr, 'LoginGraceTime 30'; +push @cfgarr, "LogLevel $loglevel"; +push @cfgarr, 'MaxStartups 5'; +push @cfgarr, 'PasswordAuthentication no'; +push @cfgarr, 'PermitEmptyPasswords no'; +push @cfgarr, 'PermitRootLogin no'; +push @cfgarr, 'PrintLastLog no'; +push @cfgarr, 'PrintMotd no'; +push @cfgarr, 'PubkeyAuthentication yes'; +push @cfgarr, 'RhostsRSAAuthentication no'; +push @cfgarr, 'RSAAuthentication no'; +push @cfgarr, 'ServerKeyBits 768'; +push @cfgarr, 'StrictModes no'; +push @cfgarr, "Subsystem sftp $sftp"; +push @cfgarr, 'SyslogFacility AUTH'; +push @cfgarr, 'UseLogin no'; +push @cfgarr, 'X11Forwarding no'; +push @cfgarr, '#'; + + +#*************************************************************************** +# Write out initial sshd configuration file for curl's tests +# +$error = dump_array($sshdconfig, @cfgarr); +if($error) { + logmsg $error; exit 1; } -# Start the server -my $rc = system "$sshd -e -D -f $conffile > log/sshd.log 2>&1"; + +#*************************************************************************** +# Verifies at run time if sshd supports a given configuration file option +# +sub sshd_supports_opt { + my ($option, $value) = @_; + my $err; + # + if((($sshdid =~ /OpenSSH/) && ($sshdvernum >= 310)) || + ($sshdid =~ /SunSSH/)) { + # ssh daemon supports command line options -t -f and -o + $err = grep /((Unsupported)|(Bad configuration)|(Deprecated)) option.*$option/, + qx($sshd -t -f $sshdconfig -o $option=$value 2>&1); + return !$err; + } + if(($sshdid =~ /OpenSSH/) && ($sshdvernum >= 299)) { + # ssh daemon supports command line options -t and -f + $err = dump_array($sshdconfig, (@cfgarr, "$option $value")); + if($err) { + logmsg $err; + return 0; + } + $err = grep /((Unsupported)|(Bad configuration)|(Deprecated)) option.*$option/, + qx($sshd -t -f $sshdconfig 2>&1); + unlink $sshdconfig; + return !$err; + } + return 0; +} + + +#*************************************************************************** +# Kerberos Authentication support may have not been built into sshd +# +if(sshd_supports_opt('KerberosAuthentication','no')) { + push @cfgarr, 'KerberosAuthentication no'; +} +if(sshd_supports_opt('KerberosGetAFSToken','no')) { + push @cfgarr, 'KerberosGetAFSToken no'; +} +if(sshd_supports_opt('KerberosOrLocalPasswd','no')) { + push @cfgarr, 'KerberosOrLocalPasswd no'; +} +if(sshd_supports_opt('KerberosTgtPassing','no')) { + push @cfgarr, 'KerberosTgtPassing no'; +} +if(sshd_supports_opt('KerberosTicketCleanup','yes')) { + push @cfgarr, 'KerberosTicketCleanup yes'; +} + + +#*************************************************************************** +# Andrew File System support may have not been built into sshd +# +if(sshd_supports_opt('AFSTokenPassing','no')) { + push @cfgarr, 'AFSTokenPassing no'; +} + + +#*************************************************************************** +# S/Key authentication support may have not been built into sshd +# +if(sshd_supports_opt('SkeyAuthentication','no')) { + push @cfgarr, 'SkeyAuthentication no'; +} + + +#*************************************************************************** +# GSSAPI Authentication support may have not been built into sshd +# +if(sshd_supports_opt('GSSAPIAuthentication','no')) { + push @cfgarr, 'GSSAPIAuthentication no'; +} +if(sshd_supports_opt('GSSAPICleanupCredentials','yes')) { + push @cfgarr, 'GSSAPICleanupCredentials yes'; +} +push @cfgarr, '#'; + + +#*************************************************************************** +# Options that might be supported or not in sshd OpenSSH 2.9.9 and later +# +if(sshd_supports_opt('AcceptEnv','')) { + push @cfgarr, 'AcceptEnv'; +} +if(sshd_supports_opt('AddressFamily','any')) { + # Address family must be specified before ListenAddress + splice @cfgarr, 13, 0, 'AddressFamily any'; +} +if(sshd_supports_opt('Compression','no')) { + push @cfgarr, 'Compression no'; +} +if(sshd_supports_opt('KeepAlive','no')) { + push @cfgarr, 'KeepAlive no'; +} +if(sshd_supports_opt('MaxAuthTries','0')) { + push @cfgarr, 'MaxAuthTries 0'; +} +if(sshd_supports_opt('PermitTunnel','no')) { + push @cfgarr, 'PermitTunnel no'; +} +if(sshd_supports_opt('PermitUserEnvironment','no')) { + push @cfgarr, 'PermitUserEnvironment no'; +} +if(sshd_supports_opt('TCPKeepAlive','no')) { + push @cfgarr, 'TCPKeepAlive no'; +} +if(sshd_supports_opt('UseDNS','no')) { + push @cfgarr, 'UseDNS no'; +} +if(sshd_supports_opt('UsePAM','no')) { + push @cfgarr, 'UsePAM no'; +} +if(sshd_supports_opt('UsePrivilegeSeparation','no')) { + push @cfgarr, 'UsePrivilegeSeparation no'; +} +if(sshd_supports_opt('X11UseLocalhost','yes')) { + push @cfgarr, 'X11UseLocalhost yes'; +} +push @cfgarr, '#'; + + +#*************************************************************************** +# Write out resulting sshd configuration file for curl's tests +# +$error = dump_array($sshdconfig, @cfgarr); +if($error) { + logmsg $error; + exit 1; +} + + +#*************************************************************************** +# Verify that sshd actually supports our generated configuration file +# +if(system "$sshd -t -f $sshdconfig > $sshdlog 2>&1") { + logmsg "sshd configuration file $sshdconfig failed verification"; + display_sshdlog(); + display_sshdconfig(); + exit 1; +} + + +#*************************************************************************** +# Generate ssh client host key database file for curl's tests +# +if(! -e $knownhosts) { + logmsg 'generating ssh client known hosts file...' if($verbose); + if(open(DSAKEYFILE, "<$hstpubkeyf")) { + my @dsahostkey = do { local $/ = ' '; }; + if(close(DSAKEYFILE)) { + if(open(KNOWNHOSTS, ">$knownhosts")) { + print KNOWNHOSTS "$listenaddr ssh-dss $dsahostkey[1]\n"; + if(!close(KNOWNHOSTS)) { + $error = "Error: cannot close file $knownhosts"; + } + } + else { + $error = "Error: cannot write file $knownhosts"; + } + } + else { + $error = "Error: cannot close file $hstpubkeyf"; + } + } + else { + $error = "Error: cannot read file $hstpubkeyf"; + } + if($error) { + logmsg $error; + exit 1; + } +} + +#*************************************************************************** +# ssh client configuration file options we might use and version support +# +# AddressFamily : OpenSSH 3.7.0 and later +# BatchMode : OpenSSH 1.2.1 and later +# BindAddress : OpenSSH 2.9.9 and later +# ChallengeResponseAuthentication : OpenSSH 2.5.0 and later +# CheckHostIP : OpenSSH 1.2.1 and later +# Cipher : OpenSSH 1.2.1 and later [3] +# Ciphers : OpenSSH 2.1.0 and later [3] +# ClearAllForwardings : OpenSSH 2.9.9 and later +# Compression : OpenSSH 1.2.1 and later +# CompressionLevel : OpenSSH 1.2.1 and later [3] +# ConnectionAttempts : OpenSSH 1.2.1 and later +# ConnectTimeout : OpenSSH 3.7.0 and later +# ControlMaster : OpenSSH 3.9.0 and later +# ControlPath : OpenSSH 3.9.0 and later +# DynamicForward : OpenSSH 2.9.0 and later +# EnableSSHKeysign : OpenSSH 3.6.0 and later +# EscapeChar : OpenSSH 1.2.1 and later [3] +# ExitOnForwardFailure : OpenSSH 4.4.0 and later +# ForwardAgent : OpenSSH 1.2.1 and later +# ForwardX11 : OpenSSH 1.2.1 and later +# ForwardX11Trusted : OpenSSH 3.8.0 and later +# GatewayPorts : OpenSSH 1.2.1 and later +# GlobalKnownHostsFile : OpenSSH 1.2.1 and later +# GSSAPIAuthentication : OpenSSH 3.7.0 and later [1][3] +# GSSAPIDelegateCredentials : OpenSSH 3.7.0 and later [1][3] +# HashKnownHosts : OpenSSH 4.0.0 and later +# Host : OpenSSH 1.2.1 and later +# HostbasedAuthentication : OpenSSH 2.9.0 and later +# HostKeyAlgorithms : OpenSSH 2.9.0 and later [3] +# HostKeyAlias : OpenSSH 2.5.0 and later [3] +# HostName : OpenSSH 1.2.1 and later +# IdentitiesOnly : OpenSSH 3.9.0 and later +# IdentityFile : OpenSSH 1.2.1 and later +# KeepAlive : OpenSSH 1.2.1 and later +# KbdInteractiveAuthentication : OpenSSH 2.3.0 and later +# KbdInteractiveDevices : OpenSSH 2.3.0 and later [3] +# LocalCommand : OpenSSH 4.3.0 and later +# LocalForward : OpenSSH 1.2.1 and later [3] +# LogLevel : OpenSSH 1.2.1 and later +# MACs : OpenSSH 2.5.0 and later [3] +# NoHostAuthenticationForLocalhost : OpenSSH 3.0.0 and later +# NumberOfPasswordPrompts : OpenSSH 1.2.1 and later +# PasswordAuthentication : OpenSSH 1.2.1 and later +# PermitLocalCommand : OpenSSH 4.3.0 and later +# Port : OpenSSH 1.2.1 and later +# PreferredAuthentications : OpenSSH 2.5.2 and later +# Protocol : OpenSSH 2.1.0 and later +# ProxyCommand : OpenSSH 1.2.1 and later [3] +# PubkeyAuthentication : OpenSSH 2.5.0 and later +# RekeyLimit : OpenSSH 3.7.0 and later +# RemoteForward : OpenSSH 1.2.1 and later [3] +# RhostsRSAAuthentication : OpenSSH 1.2.1 and later +# RSAAuthentication : OpenSSH 1.2.1 and later +# SendEnv : OpenSSH 3.9.0 and later +# ServerAliveCountMax : OpenSSH 3.8.0 and later +# ServerAliveInterval : OpenSSH 3.8.0 and later +# SmartcardDevice : OpenSSH 2.9.9 and later [1][3] +# StrictHostKeyChecking : OpenSSH 1.2.1 and later +# TCPKeepAlive : OpenSSH 3.8.0 and later +# Tunnel : OpenSSH 4.3.0 and later +# TunnelDevice : OpenSSH 4.3.0 and later [3] +# UsePAM : OpenSSH 3.7.0 and later [1][2][3] +# UsePrivilegedPort : OpenSSH 1.2.1 and later +# User : OpenSSH 1.2.1 and later +# UserKnownHostsFile : OpenSSH 1.2.1 and later +# VerifyHostKeyDNS : OpenSSH 3.8.0 and later +# XAuthLocation : OpenSSH 2.1.1 and later [3] +# +# [1] Option only available if activated at compile time +# [2] Option specific for portable versions +# [3] Option not used in our ssh client config file + + +#*************************************************************************** +# Initialize ssh config with options actually supported in OpenSSH 2.9.9 +# +logmsg 'generating ssh client config file...' if($verbose); +@cfgarr = (); +push @cfgarr, '# This is a generated file. Do not edit.'; +push @cfgarr, "# $sshverstr ssh client configuration file for curl testing"; +push @cfgarr, '#'; +push @cfgarr, 'Host *'; +push @cfgarr, '#'; +push @cfgarr, "Port $port"; +push @cfgarr, "HostName $listenaddr"; +push @cfgarr, "User $username"; +push @cfgarr, 'Protocol 2'; +push @cfgarr, '#'; +push @cfgarr, "BindAddress $listenaddr"; +push @cfgarr, "DynamicForward $socksport"; +push @cfgarr, '#'; +push @cfgarr, "IdentityFile $path/curl_client_key"; +push @cfgarr, "UserKnownHostsFile $path/$knownhosts"; +push @cfgarr, '#'; +push @cfgarr, 'BatchMode yes'; +push @cfgarr, 'ChallengeResponseAuthentication no'; +push @cfgarr, 'CheckHostIP no'; +push @cfgarr, 'ClearAllForwardings no'; +push @cfgarr, 'Compression no'; +push @cfgarr, 'ConnectionAttempts 3'; +push @cfgarr, 'ForwardAgent no'; +push @cfgarr, 'ForwardX11 no'; +push @cfgarr, 'GatewayPorts no'; +push @cfgarr, 'GlobalKnownHostsFile /dev/null'; +push @cfgarr, 'HostbasedAuthentication no'; +push @cfgarr, 'KbdInteractiveAuthentication no'; +push @cfgarr, "LogLevel $loglevel"; +push @cfgarr, 'NumberOfPasswordPrompts 0'; +push @cfgarr, 'PasswordAuthentication no'; +push @cfgarr, 'PreferredAuthentications publickey'; +push @cfgarr, 'PubkeyAuthentication yes'; +push @cfgarr, 'RhostsRSAAuthentication no'; +push @cfgarr, 'RSAAuthentication no'; +push @cfgarr, 'StrictHostKeyChecking yes'; +push @cfgarr, 'UsePrivilegedPort no'; +push @cfgarr, '#'; + + +#*************************************************************************** +# Options supported in ssh client newer than OpenSSH 2.9.9 +# + +if(($sshid =~ /OpenSSH/) && ($sshvernum >= 370)) { + push @cfgarr, 'AddressFamily any'; +} + +if((($sshid =~ /OpenSSH/) && ($sshvernum >= 370)) || + ($sshid =~ /SunSSH/)) { + push @cfgarr, 'ConnectTimeout 30'; +} + +if(($sshid =~ /OpenSSH/) && ($sshvernum >= 390)) { + push @cfgarr, 'ControlMaster no'; + push @cfgarr, 'ControlPath none'; +} + +if(($sshid =~ /OpenSSH/) && ($sshvernum >= 360)) { + push @cfgarr, 'EnableSSHKeysign no'; +} + +if(($sshid =~ /OpenSSH/) && ($sshvernum >= 440)) { + push @cfgarr, 'ExitOnForwardFailure yes'; +} + +if((($sshid =~ /OpenSSH/) && ($sshvernum >= 380)) || + ($sshid =~ /SunSSH/)) { + push @cfgarr, 'ForwardX11Trusted no'; +} + +if((($sshid =~ /OpenSSH/) && ($sshvernum >= 400)) || + ($sshid =~ /SunSSH/)) { + push @cfgarr, 'HashKnownHosts no'; +} + +if(($sshid =~ /OpenSSH/) && ($sshvernum >= 390)) { + push @cfgarr, 'IdentitiesOnly yes'; +} + +if((($sshid =~ /OpenSSH/) && ($sshvernum < 380)) || + ($sshid =~ /SunSSH/)) { + push @cfgarr, 'KeepAlive no'; +} + +if(($sshid =~ /OpenSSH/) && ($sshvernum >= 430)) { + push @cfgarr, 'LocalCommand'; +} + +if((($sshid =~ /OpenSSH/) && ($sshvernum >= 300)) || + ($sshid =~ /SunSSH/)) { + push @cfgarr, 'NoHostAuthenticationForLocalhost no'; +} + +if(($sshid =~ /OpenSSH/) && ($sshvernum >= 430)) { + push @cfgarr, 'PermitLocalCommand no'; +} + +if((($sshid =~ /OpenSSH/) && ($sshvernum >= 370)) || + ($sshid =~ /SunSSH/)) { + push @cfgarr, 'RekeyLimit 1G'; +} + +if(($sshid =~ /OpenSSH/) && ($sshvernum >= 390)) { + push @cfgarr, 'SendEnv'; +} + +if((($sshid =~ /OpenSSH/) && ($sshvernum >= 380)) || + ($sshid =~ /SunSSH/)) { + push @cfgarr, 'ServerAliveCountMax 3'; + push @cfgarr, 'ServerAliveInterval 0'; +} + +if(($sshid =~ /OpenSSH/) && ($sshvernum >= 380)) { + push @cfgarr, 'TCPKeepAlive no'; +} + +if(($sshid =~ /OpenSSH/) && ($sshvernum >= 430)) { + push @cfgarr, 'Tunnel no'; +} + +if(($sshid =~ /OpenSSH/) && ($sshvernum >= 380)) { + push @cfgarr, 'VerifyHostKeyDNS no'; +} + +push @cfgarr, '#'; + + +#*************************************************************************** +# Write out resulting ssh client configuration file for curl's tests +# +$error = dump_array($sshconfig, @cfgarr); +if($error) { + logmsg $error; + exit 1; +} +@cfgarr = (); + + +#*************************************************************************** +# Start the ssh server daemon without forking it +# +my $rc = system "$sshd -e -D -f $sshdconfig > $sshdlog 2>&1"; if($rc == -1) { - print "$sshd failed with: $!\n"; - $showfiles=1; + logmsg "$sshd failed with: $!"; } elsif($rc & 127) { - printf("$sshd died with signal %d, and %s coredump.\n", - ($rc & 127), ($rc & 128)?"a":"no"); - $showfiles=1; + logmsg sprintf("$sshd died with signal %d, and %s coredump", + ($rc & 127), ($rc & 128)?'a':'no'); } elsif($verbose && ($rc >> 8)) { - printf("$sshd exited with %d \n", $rc >> 8); + logmsg sprintf("$sshd exited with %d", $rc >> 8); } -if($showfiles) { - displayfile("log/sshd.log"); - displayfile("$conffile"); -} -unlink "log/sshd.log"; -unlink $conffile; +#*************************************************************************** +# Clean up once the server has stopped +# +unlink($hstprvkeyf, $hstpubkeyf, $cliprvkeyf, $clipubkeyf, $knownhosts); +unlink($sshdconfig, $sshconfig); -exit $rc >> 8; + +exit 0;