1#!/usr/bin/env perl 2#*************************************************************************** 3# _ _ ____ _ 4# Project ___| | | | _ \| | 5# / __| | | | |_) | | 6# | (__| |_| | _ <| |___ 7# \___|\___/|_| \_\_____| 8# 9# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 10# 11# This software is licensed as described in the file COPYING, which 12# you should have received as part of this distribution. The terms 13# are also available at https://curl.se/docs/copyright.html. 14# 15# You may opt to use, copy, modify, merge, publish, distribute and/or sell 16# copies of the Software, and permit persons to whom the Software is 17# furnished to do so, under the terms of the COPYING file. 18# 19# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 20# KIND, either express or implied. 21# 22# SPDX-License-Identifier: curl 23# 24#*************************************************************************** 25 26# Starts sshd for use in the SCP and SFTP curl test harness tests. 27# Also creates the ssh configuration files needed for these tests. 28 29use strict; 30use warnings; 31use Cwd; 32use Cwd 'abs_path'; 33use Digest::MD5; 34use Digest::MD5 'md5_hex'; 35use Digest::SHA; 36use Digest::SHA 'sha256_base64'; 37use MIME::Base64; 38use File::Basename; 39 40#*************************************************************************** 41# Variables and subs imported from sshhelp module 42# 43use sshhelp qw( 44 $sshdexe 45 $sshexe 46 $sftpsrvexe 47 $sftpexe 48 $sshkeygenexe 49 $sshdconfig 50 $sshconfig 51 $sftpconfig 52 $knownhosts 53 $sshdlog 54 $sshlog 55 $sftplog 56 $sftpcmds 57 $hstprvkeyf 58 $hstpubkeyf 59 $hstpubmd5f 60 $hstpubsha256f 61 $cliprvkeyf 62 $clipubkeyf 63 display_sshdconfig 64 display_sshconfig 65 display_sftpconfig 66 display_sshdlog 67 display_sshlog 68 display_sftplog 69 dump_array 70 find_sshd 71 find_ssh 72 find_sftpsrv 73 find_sftp 74 find_sshkeygen 75 sshversioninfo 76 ); 77 78#*************************************************************************** 79# Subs imported from serverhelp module 80# 81use serverhelp qw( 82 $logfile 83 server_pidfilename 84 server_logfilename 85 ); 86 87use pathhelp; 88 89#*************************************************************************** 90 91my $verbose = 0; # set to 1 for debugging 92my $debugprotocol = 0; # set to 1 for protocol debugging 93my $port = 8999; # our default SCP/SFTP server port 94my $listenaddr = '127.0.0.1'; # default address on which to listen 95my $ipvnum = 4; # default IP version of listener address 96my $idnum = 1; # default ssh daemon instance number 97my $proto = 'ssh'; # protocol the ssh daemon speaks 98my $path = getcwd(); # current working directory 99my $logdir = $path .'/log'; # directory for log files 100my $piddir; # directory for server config files 101my $username = $ENV{USER}; # default user 102my $pidfile; # ssh daemon pid file 103my $identity = 'curl_client_key'; # default identity file 104 105my $error; 106my @cfgarr; 107 108#*************************************************************************** 109# Returns a path of the given file name in the log directory (PiddirPath) 110# 111sub pp { 112 my $file = $_[0]; 113 return "$piddir/$file"; 114 # TODO: do Windows path conversion here 115} 116 117#*************************************************************************** 118# Save the message to the log and print it 119sub logmsg { 120 my $msg = $_[0]; 121 serverhelp::logmsg $msg; 122 print $msg; 123} 124 125#*************************************************************************** 126# Parse command line options 127# 128while(@ARGV) { 129 if($ARGV[0] eq '--verbose') { 130 $verbose = 1; 131 } 132 elsif($ARGV[0] eq '--debugprotocol') { 133 $verbose = 1; 134 $debugprotocol = 1; 135 } 136 elsif($ARGV[0] eq '--user') { 137 if($ARGV[1]) { 138 $username = $ARGV[1]; 139 shift @ARGV; 140 } 141 } 142 elsif($ARGV[0] eq '--id') { 143 if($ARGV[1]) { 144 if($ARGV[1] =~ /^(\d+)$/) { 145 $idnum = $1 if($1 > 0); 146 shift @ARGV; 147 } 148 } 149 } 150 elsif($ARGV[0] eq '--ipv4') { 151 $ipvnum = 4; 152 $listenaddr = '127.0.0.1' if($listenaddr eq '::1'); 153 } 154 elsif($ARGV[0] eq '--ipv6') { 155 $ipvnum = 6; 156 $listenaddr = '::1' if($listenaddr eq '127.0.0.1'); 157 } 158 elsif($ARGV[0] eq '--addr') { 159 if($ARGV[1]) { 160 my $tmpstr = $ARGV[1]; 161 if($tmpstr =~ /^(\d\d?\d?)\.(\d\d?\d?)\.(\d\d?\d?)\.(\d\d?\d?)$/) { 162 $listenaddr = "$1.$2.$3.$4" if($ipvnum == 4); 163 shift @ARGV; 164 } 165 elsif($ipvnum == 6) { 166 $listenaddr = $tmpstr; 167 $listenaddr =~ s/^\[(.*)\]$/$1/; 168 shift @ARGV; 169 } 170 } 171 } 172 elsif($ARGV[0] eq '--pidfile') { 173 if($ARGV[1]) { 174 $pidfile = "$path/". $ARGV[1]; 175 shift @ARGV; 176 } 177 } 178 elsif($ARGV[0] eq '--logdir') { 179 if($ARGV[1]) { 180 $logdir = "$path/". $ARGV[1]; 181 shift @ARGV; 182 } 183 } 184 elsif($ARGV[0] eq '--sshport') { 185 if($ARGV[1]) { 186 if($ARGV[1] =~ /^(\d+)$/) { 187 $port = $1; 188 shift @ARGV; 189 } 190 } 191 } 192 else { 193 print STDERR "\nWarning: sshserver.pl unknown parameter: $ARGV[0]\n"; 194 } 195 shift @ARGV; 196} 197 198#*************************************************************************** 199# Initialize command line option dependent variables 200# 201 202#*************************************************************************** 203# Default ssh daemon pid file name & directory 204# 205if($pidfile) { 206 # Use our pidfile directory to store server config files 207 $piddir = dirname($pidfile); 208} 209else { 210 # Use the current directory to store server config files 211 $piddir = $path; 212 $pidfile = server_pidfilename($piddir, $proto, $ipvnum, $idnum); 213} 214 215#*************************************************************************** 216# ssh and sftp server log file names 217# 218$sshdlog = server_logfilename($logdir, 'ssh', $ipvnum, $idnum); 219$sftplog = server_logfilename($logdir, 'sftp', $ipvnum, $idnum); 220$logfile = "$logdir/sshserver.log"; # used by logmsg 221 222#*************************************************************************** 223# Logging level for ssh server and client 224# 225my $loglevel = $debugprotocol?'DEBUG3':'DEBUG2'; 226 227 228#*************************************************************************** 229# Validate username 230# 231if(!$username) { 232 $error = 'Will not run ssh server without a user name'; 233} 234elsif($username eq 'root') { 235 $error = 'Will not run ssh server as root to mitigate security risks'; 236} 237if($error) { 238 logmsg "$error\n"; 239 exit 1; 240} 241 242 243#*************************************************************************** 244# Find out ssh daemon canonical file name 245# 246my $sshd = find_sshd(); 247if(!$sshd) { 248 logmsg "cannot find $sshdexe\n"; 249 exit 1; 250} 251 252 253#*************************************************************************** 254# Find out ssh daemon version info 255# 256my ($sshdid, $sshdvernum, $sshdverstr, $sshderror) = sshversioninfo($sshd); 257if(!$sshdid) { 258 # Not an OpenSSH or SunSSH ssh daemon 259 logmsg "$sshderror\n" if($verbose); 260 logmsg "SCP and SFTP tests require OpenSSH 2.9.9 or later\n"; 261 exit 1; 262} 263logmsg "ssh server found $sshd is $sshdverstr\n" if($verbose); 264 265 266#*************************************************************************** 267# ssh daemon command line options we might use and version support 268# 269# -e: log stderr : OpenSSH 2.9.0 and later 270# -f: sshd config file : OpenSSH 1.2.1 and later 271# -D: no daemon forking : OpenSSH 2.5.0 and later 272# -o: command-line option : OpenSSH 3.1.0 and later 273# -t: test config file : OpenSSH 2.9.9 and later 274# -?: sshd version info : OpenSSH 1.2.1 and later 275# 276# -e: log stderr : SunSSH 1.0.0 and later 277# -f: sshd config file : SunSSH 1.0.0 and later 278# -D: no daemon forking : SunSSH 1.0.0 and later 279# -o: command-line option : SunSSH 1.0.0 and later 280# -t: test config file : SunSSH 1.0.0 and later 281# -?: sshd version info : SunSSH 1.0.0 and later 282 283 284#*************************************************************************** 285# Verify minimum ssh daemon version 286# 287if((($sshdid =~ /OpenSSH/) && ($sshdvernum < 299)) || 288 (($sshdid =~ /SunSSH/) && ($sshdvernum < 100))) { 289 logmsg "SCP and SFTP tests require OpenSSH 2.9.9 or later\n"; 290 exit 1; 291} 292 293 294#*************************************************************************** 295# Find out sftp server plugin canonical file name 296# 297my $sftpsrv = find_sftpsrv(); 298if(!$sftpsrv) { 299 logmsg "cannot find $sftpsrvexe\n"; 300 exit 1; 301} 302logmsg "sftp server plugin found $sftpsrv\n" if($verbose); 303 304 305#*************************************************************************** 306# Find out sftp client canonical file name 307# 308my $sftp = find_sftp(); 309if(!$sftp) { 310 logmsg "cannot find $sftpexe\n"; 311 exit 1; 312} 313logmsg "sftp client found $sftp\n" if($verbose); 314 315 316#*************************************************************************** 317# Find out ssh keygen canonical file name 318# 319my $sshkeygen = find_sshkeygen(); 320if(!$sshkeygen) { 321 logmsg "cannot find $sshkeygenexe\n"; 322 exit 1; 323} 324logmsg "ssh keygen found $sshkeygen\n" if($verbose); 325 326 327#*************************************************************************** 328# Find out ssh client canonical file name 329# 330my $ssh = find_ssh(); 331if(!$ssh) { 332 logmsg "cannot find $sshexe\n"; 333 exit 1; 334} 335 336 337#*************************************************************************** 338# Find out ssh client version info 339# 340my ($sshid, $sshvernum, $sshverstr, $ssherror) = sshversioninfo($ssh); 341if(!$sshid) { 342 # Not an OpenSSH or SunSSH ssh client 343 logmsg "$ssherror\n" if($verbose); 344 logmsg "SCP and SFTP tests require OpenSSH 2.9.9 or later\n"; 345 exit 1; 346} 347logmsg "ssh client found $ssh is $sshverstr\n" if($verbose); 348 349 350#*************************************************************************** 351# ssh client command line options we might use and version support 352# 353# -D: dynamic app port forwarding : OpenSSH 2.9.9 and later 354# -F: ssh config file : OpenSSH 2.9.9 and later 355# -N: no shell/command : OpenSSH 2.1.0 and later 356# -p: connection port : OpenSSH 1.2.1 and later 357# -v: verbose messages : OpenSSH 1.2.1 and later 358# -vv: increase verbosity : OpenSSH 2.3.0 and later 359# -V: ssh version info : OpenSSH 1.2.1 and later 360# 361# -D: dynamic app port forwarding : SunSSH 1.0.0 and later 362# -F: ssh config file : SunSSH 1.0.0 and later 363# -N: no shell/command : SunSSH 1.0.0 and later 364# -p: connection port : SunSSH 1.0.0 and later 365# -v: verbose messages : SunSSH 1.0.0 and later 366# -vv: increase verbosity : SunSSH 1.0.0 and later 367# -V: ssh version info : SunSSH 1.0.0 and later 368 369 370#*************************************************************************** 371# Verify minimum ssh client version 372# 373if((($sshid =~ /OpenSSH/) && ($sshvernum < 299)) || 374 (($sshid =~ /SunSSH/) && ($sshvernum < 100))) { 375 logmsg "SCP and SFTP tests require OpenSSH 2.9.9 or later\n"; 376 exit 1; 377} 378 379 380#*************************************************************************** 381# ssh keygen command line options we actually use and version support 382# 383# -C: identity comment : OpenSSH 1.2.1 and later 384# -f: key filename : OpenSSH 1.2.1 and later 385# -N: new passphrase : OpenSSH 1.2.1 and later 386# -q: quiet keygen : OpenSSH 1.2.1 and later 387# -t: key type : OpenSSH 2.5.0 and later 388# 389# -C: identity comment : SunSSH 1.0.0 and later 390# -f: key filename : SunSSH 1.0.0 and later 391# -N: new passphrase : SunSSH 1.0.0 and later 392# -q: quiet keygen : SunSSH 1.0.0 and later 393# -t: key type : SunSSH 1.0.0 and later 394 395$sshdconfig = pp($sshdconfig); 396$sshconfig = pp($sshconfig); 397$sftpconfig = pp($sftpconfig); 398 399#*************************************************************************** 400# Generate host and client key files for curl's tests 401# 402if((! -e pp($hstprvkeyf)) || (! -s pp($hstprvkeyf)) || 403 (! -e pp($hstpubkeyf)) || (! -s pp($hstpubkeyf)) || 404 (! -e pp($hstpubmd5f)) || (! -s pp($hstpubmd5f)) || 405 (! -e pp($hstpubsha256f)) || (! -s pp($hstpubsha256f)) || 406 (! -e pp($cliprvkeyf)) || (! -s pp($cliprvkeyf)) || 407 (! -e pp($clipubkeyf)) || (! -s pp($clipubkeyf))) { 408 # Make sure all files are gone so ssh-keygen doesn't complain 409 unlink(pp($hstprvkeyf), pp($hstpubkeyf), pp($hstpubmd5f), 410 pp($hstpubsha256f), pp($cliprvkeyf), pp($clipubkeyf)); 411 logmsg "generating host keys...\n" if($verbose); 412 if(system "\"$sshkeygen\" -q -t rsa -f " . pp($hstprvkeyf) . " -C 'curl test server' -N ''") { 413 logmsg "Could not generate host key\n"; 414 exit 1; 415 } 416 logmsg "generating client keys...\n" if($verbose); 417 if(system "\"$sshkeygen\" -q -t rsa -f " . pp($cliprvkeyf) . " -C 'curl test client' -N ''") { 418 logmsg "Could not generate client key\n"; 419 exit 1; 420 } 421 # Make sure that permissions are restricted so openssh doesn't complain 422 system "chmod 600 " . pp($hstprvkeyf); 423 system "chmod 600 " . pp($cliprvkeyf); 424 if(pathhelp::os_is_win()) { 425 # https://ss64.com/nt/icacls.html 426 $ENV{'MSYS2_ARG_CONV_EXCL'} = '/reset'; 427 system("icacls \"" . pathhelp::sys_native_abs_path(pp($hstprvkeyf)) . "\" /reset"); 428 system("icacls \"" . pathhelp::sys_native_abs_path(pp($hstprvkeyf)) . "\" /grant:r \"$username:(R)\""); 429 system("icacls \"" . pathhelp::sys_native_abs_path(pp($hstprvkeyf)) . "\" /inheritance:r"); 430 } 431 # Save md5 and sha256 hashes of public host key 432 open(my $rsakeyfile, "<", pp($hstpubkeyf)); 433 my @rsahostkey = do { local $/ = ' '; <$rsakeyfile> }; 434 close($rsakeyfile); 435 if(!$rsahostkey[1]) { 436 logmsg "Failed parsing base64 encoded RSA host key\n"; 437 exit 1; 438 } 439 open(my $pubmd5file, ">", pp($hstpubmd5f)); 440 print $pubmd5file md5_hex(decode_base64($rsahostkey[1])); 441 close($pubmd5file); 442 if((! -e pp($hstpubmd5f)) || (! -s pp($hstpubmd5f))) { 443 logmsg "Failed writing md5 hash of RSA host key\n"; 444 exit 1; 445 } 446 open(my $pubsha256file, ">", pp($hstpubsha256f)); 447 print $pubsha256file sha256_base64(decode_base64($rsahostkey[1])); 448 close($pubsha256file); 449 if((! -e pp($hstpubsha256f)) || (! -s pp($hstpubsha256f))) { 450 logmsg "Failed writing sha256 hash of RSA host key\n"; 451 exit 1; 452 } 453} 454 455 456#*************************************************************************** 457# Convert paths for curl's tests running on Windows with Cygwin/MSYS OpenSSH 458# 459my $clipubkeyf_config; 460my $hstprvkeyf_config; 461my $pidfile_config; 462my $sftpsrv_config; 463my $sshdconfig_abs; 464if ($sshdid =~ /OpenSSH-Windows/) { 465 # Ensure to use native Windows paths with OpenSSH for Windows 466 $clipubkeyf_config = pathhelp::sys_native_abs_path(pp($clipubkeyf)); 467 $hstprvkeyf_config = pathhelp::sys_native_abs_path(pp($hstprvkeyf)); 468 $pidfile_config = pathhelp::sys_native_abs_path($pidfile); 469 $sftpsrv_config = pathhelp::sys_native_abs_path($sftpsrv); 470 $sshdconfig_abs = pathhelp::sys_native_abs_path($sshdconfig); 471} 472elsif (pathhelp::os_is_win()) { 473 # Ensure to use MinGW/Cygwin paths 474 $clipubkeyf_config = pathhelp::build_sys_abs_path(pp($clipubkeyf)); 475 $hstprvkeyf_config = pathhelp::build_sys_abs_path(pp($hstprvkeyf)); 476 $pidfile_config = pathhelp::build_sys_abs_path($pidfile); 477 $sftpsrv_config = "internal-sftp"; 478 $sshdconfig_abs = pathhelp::build_sys_abs_path($sshdconfig); 479} 480else { 481 $clipubkeyf_config = abs_path(pp($clipubkeyf)); 482 $hstprvkeyf_config = abs_path(pp($hstprvkeyf)); 483 $pidfile_config = $pidfile; 484 $sftpsrv_config = $sftpsrv; 485 $sshdconfig_abs = abs_path($sshdconfig); 486} 487 488#*************************************************************************** 489# ssh daemon configuration file options we might use and version support 490# 491# AFSTokenPassing : OpenSSH 1.2.1 and later [1] 492# AddressFamily : OpenSSH 4.0.0 and later 493# AllowTcpForwarding : OpenSSH 2.3.0 and later 494# AllowUsers : OpenSSH 1.2.1 and later 495# AuthorizedKeysFile : OpenSSH 2.9.9 and later 496# AuthorizedKeysFile2 : OpenSSH 2.9.9 till 5.9 497# Banner : OpenSSH 2.5.0 and later 498# ChallengeResponseAuthentication : OpenSSH 2.5.0 and later 499# Ciphers : OpenSSH 2.1.0 and later [3] 500# ClientAliveCountMax : OpenSSH 2.9.0 and later 501# ClientAliveInterval : OpenSSH 2.9.0 and later 502# Compression : OpenSSH 3.3.0 and later 503# DenyUsers : OpenSSH 1.2.1 and later 504# ForceCommand : OpenSSH 4.4.0 and later [3] 505# GatewayPorts : OpenSSH 2.1.0 and later 506# GSSAPIAuthentication : OpenSSH 3.7.0 and later [1] 507# GSSAPICleanupCredentials : OpenSSH 3.8.0 and later [1] 508# GSSAPIKeyExchange : SunSSH 1.0.0 and later [1] 509# GSSAPIStoreDelegatedCredentials : SunSSH 1.0.0 and later [1] 510# GSSCleanupCreds : SunSSH 1.0.0 and later [1] 511# GSSUseSessionCredCache : SunSSH 1.0.0 and later [1] 512# HostbasedAuthentication : OpenSSH 2.9.0 and later 513# HostbasedUsesNameFromPacketOnly : OpenSSH 2.9.0 and later 514# HostKey : OpenSSH 1.2.1 and later 515# IgnoreRhosts : OpenSSH 1.2.1 and later 516# IgnoreUserKnownHosts : OpenSSH 1.2.1 and later 517# KbdInteractiveAuthentication : OpenSSH 2.3.0 and later 518# KeepAlive : OpenSSH 1.2.1 and later 519# KerberosAuthentication : OpenSSH 1.2.1 and later [1] 520# KerberosGetAFSToken : OpenSSH 3.8.0 and later [1] 521# KerberosOrLocalPasswd : OpenSSH 1.2.1 and later [1] 522# KerberosTgtPassing : OpenSSH 1.2.1 and later [1] 523# KerberosTicketCleanup : OpenSSH 1.2.1 and later [1] 524# KeyRegenerationInterval : OpenSSH 1.2.1 till 7.3 525# ListenAddress : OpenSSH 1.2.1 and later 526# LoginGraceTime : OpenSSH 1.2.1 and later 527# LogLevel : OpenSSH 1.2.1 and later 528# LookupClientHostnames : SunSSH 1.0.0 and later 529# MACs : OpenSSH 2.5.0 and later [3] 530# Match : OpenSSH 4.4.0 and later [3] 531# MaxAuthTries : OpenSSH 3.9.0 and later 532# MaxStartups : OpenSSH 2.2.0 and later 533# PAMAuthenticationViaKbdInt : OpenSSH 2.9.0 and later [2] 534# PasswordAuthentication : OpenSSH 1.2.1 and later 535# PermitEmptyPasswords : OpenSSH 1.2.1 and later 536# PermitOpen : OpenSSH 4.4.0 and later [3] 537# PermitRootLogin : OpenSSH 1.2.1 and later 538# PermitTunnel : OpenSSH 4.3.0 and later 539# PermitUserEnvironment : OpenSSH 3.5.0 and later 540# PidFile : OpenSSH 2.1.0 and later 541# Port : OpenSSH 1.2.1 and later 542# PrintLastLog : OpenSSH 2.9.0 and later 543# PrintMotd : OpenSSH 1.2.1 and later 544# Protocol : OpenSSH 2.1.0 and later 545# PubkeyAuthentication : OpenSSH 2.5.0 and later 546# RhostsAuthentication : OpenSSH 1.2.1 and later 547# RhostsRSAAuthentication : OpenSSH 1.2.1 till 7.3 548# RSAAuthentication : OpenSSH 1.2.1 till 7.3 549# ServerKeyBits : OpenSSH 1.2.1 till 7.3 550# SkeyAuthentication : OpenSSH 1.2.1 and later [1] 551# StrictModes : OpenSSH 1.2.1 and later 552# Subsystem : OpenSSH 2.2.0 and later 553# SyslogFacility : OpenSSH 1.2.1 and later 554# TCPKeepAlive : OpenSSH 3.8.0 and later 555# UseDNS : OpenSSH 3.7.0 and later 556# UseLogin : OpenSSH 1.2.1 till 7.3 557# UsePAM : OpenSSH 3.7.0 and later [1][2] 558# UsePrivilegeSeparation : OpenSSH 3.2.2 and later 559# VerifyReverseMapping : OpenSSH 3.1.0 and later 560# X11DisplayOffset : OpenSSH 1.2.1 and later [3] 561# X11Forwarding : OpenSSH 1.2.1 and later 562# X11UseLocalhost : OpenSSH 3.1.0 and later 563# XAuthLocation : OpenSSH 2.1.1 and later [3] 564# 565# [1] Option only available if activated at compile time 566# [2] Option specific for portable versions 567# [3] Option not used in our ssh server config file 568 569 570#*************************************************************************** 571# Initialize sshd config with options actually supported in OpenSSH 2.9.9 572# 573logmsg "generating ssh server config file...\n" if($verbose); 574@cfgarr = (); 575push @cfgarr, '# This is a generated file. Do not edit.'; 576push @cfgarr, "# $sshdverstr sshd configuration file for curl testing"; 577push @cfgarr, '#'; 578 579# AllowUsers and DenyUsers options should use lowercase on Windows 580# and do not support quotes around values for some unknown reason. 581if ($sshdid =~ /OpenSSH-Windows/) { 582 my $username_lc = lc $username; 583 push @cfgarr, "AllowUsers " . $username_lc =~ s/ /\?/gr; 584 if (exists $ENV{USERDOMAIN}) { 585 my $userdomain_lc = lc $ENV{USERDOMAIN}; 586 $username_lc = "$userdomain_lc\\$username_lc"; 587 $username_lc =~ s/ /\?/g; # replace space with ? 588 push @cfgarr, "AllowUsers " . $username_lc =~ s/ /\?/gr; 589 } 590} else { 591 push @cfgarr, "AllowUsers $username"; 592} 593 594push @cfgarr, "AuthorizedKeysFile $clipubkeyf_config"; 595if(!($sshdid =~ /OpenSSH/) || ($sshdvernum <= 730)) { 596 push @cfgarr, "AuthorizedKeysFile2 $clipubkeyf_config"; 597} 598push @cfgarr, "HostKey $hstprvkeyf_config"; 599if ($sshdid !~ /OpenSSH-Windows/) { 600 push @cfgarr, "PidFile $pidfile_config"; 601 push @cfgarr, '#'; 602} 603if(($sshdid =~ /OpenSSH/) && ($sshdvernum >= 880)) { 604 push @cfgarr, 'HostKeyAlgorithms +ssh-rsa'; 605 push @cfgarr, 'PubkeyAcceptedKeyTypes +ssh-rsa'; 606} 607push @cfgarr, '#'; 608push @cfgarr, "Port $port"; 609push @cfgarr, "ListenAddress $listenaddr"; 610push @cfgarr, 'Protocol 2'; 611push @cfgarr, '#'; 612push @cfgarr, 'AllowTcpForwarding yes'; 613push @cfgarr, 'Banner none'; 614push @cfgarr, 'ChallengeResponseAuthentication no'; 615push @cfgarr, 'ClientAliveCountMax 3'; 616push @cfgarr, 'ClientAliveInterval 0'; 617push @cfgarr, 'GatewayPorts no'; 618push @cfgarr, 'HostbasedAuthentication no'; 619push @cfgarr, 'HostbasedUsesNameFromPacketOnly no'; 620push @cfgarr, 'IgnoreRhosts yes'; 621push @cfgarr, 'IgnoreUserKnownHosts yes'; 622push @cfgarr, 'LoginGraceTime 30'; 623push @cfgarr, "LogLevel $loglevel"; 624push @cfgarr, 'MaxStartups 5'; 625push @cfgarr, 'PasswordAuthentication no'; 626push @cfgarr, 'PermitEmptyPasswords no'; 627push @cfgarr, 'PermitRootLogin no'; 628push @cfgarr, 'PrintLastLog no'; 629push @cfgarr, 'PrintMotd no'; 630push @cfgarr, 'PubkeyAuthentication yes'; 631push @cfgarr, 'StrictModes no'; 632push @cfgarr, "Subsystem sftp \"$sftpsrv_config\""; 633push @cfgarr, 'SyslogFacility AUTH'; 634if(!($sshdid =~ /OpenSSH/) || ($sshdvernum <= 730)) { 635 push @cfgarr, 'KeyRegenerationInterval 0'; 636 push @cfgarr, 'RhostsRSAAuthentication no'; 637 push @cfgarr, 'RSAAuthentication no'; 638 push @cfgarr, 'ServerKeyBits 768'; 639 push @cfgarr, 'UseLogin no'; 640} 641push @cfgarr, 'X11Forwarding no'; 642push @cfgarr, '#'; 643 644 645#*************************************************************************** 646# Write out initial sshd configuration file for curl's tests 647# 648$error = dump_array($sshdconfig, @cfgarr); 649if($error) { 650 logmsg "$error\n"; 651 exit 1; 652} 653 654 655#*************************************************************************** 656# Verifies at run time if sshd supports a given configuration file option 657# 658sub sshd_supports_opt { 659 my ($option, $value) = @_; 660 my $err; 661 # 662 if((($sshdid =~ /OpenSSH/) && ($sshdvernum >= 310)) || 663 ($sshdid =~ /SunSSH/)) { 664 # ssh daemon supports command line options -t -f and -o 665 $err = grep /((Unsupported)|(Bad configuration)|(Deprecated)) option.*$option/, 666 `\"$sshd\" -t -f $sshdconfig_abs -o \"$option=$value\" 2>&1`; 667 return !$err; 668 } 669 if(($sshdid =~ /OpenSSH/) && ($sshdvernum >= 299)) { 670 # ssh daemon supports command line options -t and -f 671 $err = dump_array($sshdconfig, (@cfgarr, "$option $value")); 672 if($err) { 673 logmsg "$err\n"; 674 return 0; 675 } 676 $err = grep /((Unsupported)|(Bad configuration)|(Deprecated)) option.*$option/, 677 `\"$sshd\" -t -f $sshdconfig_abs 2>&1`; 678 unlink $sshdconfig; 679 return !$err; 680 } 681 return 0; 682} 683 684 685#*************************************************************************** 686# Kerberos Authentication support may have not been built into sshd 687# 688if(sshd_supports_opt('KerberosAuthentication','no')) { 689 push @cfgarr, 'KerberosAuthentication no'; 690} 691if(sshd_supports_opt('KerberosGetAFSToken','no')) { 692 push @cfgarr, 'KerberosGetAFSToken no'; 693} 694if(sshd_supports_opt('KerberosOrLocalPasswd','no')) { 695 push @cfgarr, 'KerberosOrLocalPasswd no'; 696} 697if(sshd_supports_opt('KerberosTgtPassing','no')) { 698 push @cfgarr, 'KerberosTgtPassing no'; 699} 700if(sshd_supports_opt('KerberosTicketCleanup','yes')) { 701 push @cfgarr, 'KerberosTicketCleanup yes'; 702} 703 704 705#*************************************************************************** 706# Andrew File System support may have not been built into sshd 707# 708if(sshd_supports_opt('AFSTokenPassing','no')) { 709 push @cfgarr, 'AFSTokenPassing no'; 710} 711 712 713#*************************************************************************** 714# S/Key authentication support may have not been built into sshd 715# 716if(sshd_supports_opt('SkeyAuthentication','no')) { 717 push @cfgarr, 'SkeyAuthentication no'; 718} 719 720 721#*************************************************************************** 722# GSSAPI Authentication support may have not been built into sshd 723# 724my $sshd_builtwith_GSSAPI; 725if(sshd_supports_opt('GSSAPIAuthentication','no')) { 726 push @cfgarr, 'GSSAPIAuthentication no'; 727 $sshd_builtwith_GSSAPI = 1; 728} 729if(sshd_supports_opt('GSSAPICleanupCredentials','yes')) { 730 push @cfgarr, 'GSSAPICleanupCredentials yes'; 731} 732if(sshd_supports_opt('GSSAPIKeyExchange','no')) { 733 push @cfgarr, 'GSSAPIKeyExchange no'; 734} 735if(sshd_supports_opt('GSSAPIStoreDelegatedCredentials','no')) { 736 push @cfgarr, 'GSSAPIStoreDelegatedCredentials no'; 737} 738if(sshd_supports_opt('GSSCleanupCreds','yes')) { 739 push @cfgarr, 'GSSCleanupCreds yes'; 740} 741if(sshd_supports_opt('GSSUseSessionCredCache','no')) { 742 push @cfgarr, 'GSSUseSessionCredCache no'; 743} 744push @cfgarr, '#'; 745 746 747#*************************************************************************** 748# Options that might be supported or not in sshd OpenSSH 2.9.9 and later 749# 750if(sshd_supports_opt('AddressFamily','any')) { 751 # Address family must be specified before ListenAddress 752 splice @cfgarr, 11, 0, 'AddressFamily any'; 753} 754if(sshd_supports_opt('Compression','no')) { 755 push @cfgarr, 'Compression no'; 756} 757if(sshd_supports_opt('KbdInteractiveAuthentication','no')) { 758 push @cfgarr, 'KbdInteractiveAuthentication no'; 759} 760if(sshd_supports_opt('KeepAlive','no')) { 761 push @cfgarr, 'KeepAlive no'; 762} 763if(sshd_supports_opt('LookupClientHostnames','no')) { 764 push @cfgarr, 'LookupClientHostnames no'; 765} 766if(sshd_supports_opt('MaxAuthTries','10')) { 767 push @cfgarr, 'MaxAuthTries 10'; 768} 769if(sshd_supports_opt('PAMAuthenticationViaKbdInt','no')) { 770 push @cfgarr, 'PAMAuthenticationViaKbdInt no'; 771} 772if(sshd_supports_opt('PermitTunnel','no')) { 773 push @cfgarr, 'PermitTunnel no'; 774} 775if(sshd_supports_opt('PermitUserEnvironment','no')) { 776 push @cfgarr, 'PermitUserEnvironment no'; 777} 778if(sshd_supports_opt('RhostsAuthentication','no')) { 779 push @cfgarr, 'RhostsAuthentication no'; 780} 781if(sshd_supports_opt('TCPKeepAlive','no')) { 782 push @cfgarr, 'TCPKeepAlive no'; 783} 784if(sshd_supports_opt('UseDNS','no')) { 785 push @cfgarr, 'UseDNS no'; 786} 787if(sshd_supports_opt('UsePAM','no')) { 788 push @cfgarr, 'UsePAM no'; 789} 790 791if($sshdid =~ /OpenSSH/) { 792 # http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=6492415 793 if(sshd_supports_opt('UsePrivilegeSeparation','no')) { 794 push @cfgarr, 'UsePrivilegeSeparation no'; 795 } 796} 797 798if(sshd_supports_opt('VerifyReverseMapping','no')) { 799 push @cfgarr, 'VerifyReverseMapping no'; 800} 801if(sshd_supports_opt('X11UseLocalhost','yes')) { 802 push @cfgarr, 'X11UseLocalhost yes'; 803} 804push @cfgarr, '#'; 805 806 807#*************************************************************************** 808# Write out resulting sshd configuration file for curl's tests 809# 810$error = dump_array($sshdconfig, @cfgarr); 811if($error) { 812 logmsg "$error\n"; 813 exit 1; 814} 815 816 817#*************************************************************************** 818# Verify that sshd actually supports our generated configuration file 819# 820if(system "\"$sshd\" -t -f $sshdconfig_abs > $sshdlog 2>&1") { 821 logmsg "sshd configuration file $sshdconfig failed verification\n"; 822 display_sshdlog(); 823 display_sshdconfig(); 824 exit 1; 825} 826 827 828#*************************************************************************** 829# Generate ssh client host key database file for curl's tests 830# 831if((! -e pp($knownhosts)) || (! -s pp($knownhosts))) { 832 logmsg "generating ssh client known hosts file...\n" if($verbose); 833 unlink(pp($knownhosts)); 834 if(open(my $rsakeyfile, "<", pp($hstpubkeyf))) { 835 my @rsahostkey = do { local $/ = ' '; <$rsakeyfile> }; 836 if(close($rsakeyfile)) { 837 if(open(my $knownhostsh, ">", pp($knownhosts))) { 838 print $knownhostsh "$listenaddr ssh-rsa $rsahostkey[1]\n"; 839 if(!close($knownhostsh)) { 840 $error = "Error: cannot close file $knownhosts"; 841 } 842 } 843 else { 844 $error = "Error: cannot write file $knownhosts"; 845 } 846 } 847 else { 848 $error = "Error: cannot close file $hstpubkeyf"; 849 } 850 } 851 else { 852 $error = "Error: cannot read file $hstpubkeyf"; 853 } 854 if($error) { 855 logmsg "$error\n"; 856 exit 1; 857 } 858} 859 860 861#*************************************************************************** 862# Convert paths for curl's tests running on Windows using Cygwin OpenSSH 863# 864my $identity_config; 865my $knownhosts_config; 866if ($sshdid =~ /OpenSSH-Windows/) { 867 # Ensure to use native Windows paths with OpenSSH for Windows 868 $identity_config = pathhelp::sys_native_abs_path(pp($identity)); 869 $knownhosts_config = pathhelp::sys_native_abs_path(pp($knownhosts)); 870} 871elsif (pathhelp::os_is_win()) { 872 # Ensure to use MinGW/Cygwin paths 873 $identity_config = pathhelp::build_sys_abs_path(pp($identity)); 874 $knownhosts_config = pathhelp::build_sys_abs_path(pp($knownhosts)); 875} 876else { 877 $identity_config = abs_path(pp($identity)); 878 $knownhosts_config = abs_path(pp($knownhosts)); 879} 880 881 882#*************************************************************************** 883# ssh client configuration file options we might use and version support 884# 885# AddressFamily : OpenSSH 3.7.0 and later 886# BatchMode : OpenSSH 1.2.1 and later 887# BindAddress : OpenSSH 2.9.9 and later 888# ChallengeResponseAuthentication : OpenSSH 2.5.0 and later 889# CheckHostIP : OpenSSH 1.2.1 and later 890# Cipher : OpenSSH 1.2.1 and later [3] 891# Ciphers : OpenSSH 2.1.0 and later [3] 892# ClearAllForwardings : OpenSSH 2.9.9 and later 893# Compression : OpenSSH 1.2.1 and later 894# CompressionLevel : OpenSSH 1.2.1 and later [3] 895# ConnectionAttempts : OpenSSH 1.2.1 and later 896# ConnectTimeout : OpenSSH 3.7.0 and later 897# ControlMaster : OpenSSH 3.9.0 and later 898# ControlPath : OpenSSH 3.9.0 and later 899# DisableBanner : SunSSH 1.2.0 and later 900# DynamicForward : OpenSSH 2.9.0 and later 901# EnableSSHKeysign : OpenSSH 3.6.0 and later 902# EscapeChar : OpenSSH 1.2.1 and later [3] 903# ExitOnForwardFailure : OpenSSH 4.4.0 and later 904# ForwardAgent : OpenSSH 1.2.1 and later 905# ForwardX11 : OpenSSH 1.2.1 and later 906# ForwardX11Trusted : OpenSSH 3.8.0 and later 907# GatewayPorts : OpenSSH 1.2.1 and later 908# GlobalKnownHostsFile : OpenSSH 1.2.1 and later 909# GSSAPIAuthentication : OpenSSH 3.7.0 and later [1] 910# GSSAPIDelegateCredentials : OpenSSH 3.7.0 and later [1] 911# HashKnownHosts : OpenSSH 4.0.0 and later 912# Host : OpenSSH 1.2.1 and later 913# HostbasedAuthentication : OpenSSH 2.9.0 and later 914# HostKeyAlgorithms : OpenSSH 2.9.0 and later [3] 915# HostKeyAlias : OpenSSH 2.5.0 and later [3] 916# HostName : OpenSSH 1.2.1 and later 917# IdentitiesOnly : OpenSSH 3.9.0 and later 918# IdentityFile : OpenSSH 1.2.1 and later 919# IgnoreIfUnknown : SunSSH 1.2.0 and later 920# KeepAlive : OpenSSH 1.2.1 and later 921# KbdInteractiveAuthentication : OpenSSH 2.3.0 and later 922# KbdInteractiveDevices : OpenSSH 2.3.0 and later [3] 923# LocalCommand : OpenSSH 4.3.0 and later [3] 924# LocalForward : OpenSSH 1.2.1 and later [3] 925# LogLevel : OpenSSH 1.2.1 and later 926# MACs : OpenSSH 2.5.0 and later [3] 927# NoHostAuthenticationForLocalhost : OpenSSH 3.0.0 and later 928# NumberOfPasswordPrompts : OpenSSH 1.2.1 and later 929# PasswordAuthentication : OpenSSH 1.2.1 and later 930# PermitLocalCommand : OpenSSH 4.3.0 and later 931# Port : OpenSSH 1.2.1 and later 932# PreferredAuthentications : OpenSSH 2.5.2 and later 933# Protocol : OpenSSH 2.1.0 and later 934# ProxyCommand : OpenSSH 1.2.1 and later [3] 935# PubkeyAuthentication : OpenSSH 2.5.0 and later 936# RekeyLimit : OpenSSH 3.7.0 and later 937# RemoteForward : OpenSSH 1.2.1 and later [3] 938# RhostsRSAAuthentication : OpenSSH 1.2.1 and later 939# RSAAuthentication : OpenSSH 1.2.1 and later 940# ServerAliveCountMax : OpenSSH 3.8.0 and later 941# ServerAliveInterval : OpenSSH 3.8.0 and later 942# SmartcardDevice : OpenSSH 2.9.9 and later [1][3] 943# StrictHostKeyChecking : OpenSSH 1.2.1 and later 944# TCPKeepAlive : OpenSSH 3.8.0 and later 945# Tunnel : OpenSSH 4.3.0 and later 946# TunnelDevice : OpenSSH 4.3.0 and later [3] 947# UsePAM : OpenSSH 3.7.0 and later [1][2][3] 948# UsePrivilegedPort : OpenSSH 1.2.1 and later 949# User : OpenSSH 1.2.1 and later 950# UserKnownHostsFile : OpenSSH 1.2.1 and later 951# VerifyHostKeyDNS : OpenSSH 3.8.0 and later 952# XAuthLocation : OpenSSH 2.1.1 and later [3] 953# 954# [1] Option only available if activated at compile time 955# [2] Option specific for portable versions 956# [3] Option not used in our ssh client config file 957 958 959#*************************************************************************** 960# Initialize ssh config with options actually supported in OpenSSH 2.9.9 961# 962logmsg "generating ssh client config file...\n" if($verbose); 963@cfgarr = (); 964push @cfgarr, '# This is a generated file. Do not edit.'; 965push @cfgarr, "# $sshverstr ssh client configuration file for curl testing"; 966push @cfgarr, '#'; 967push @cfgarr, 'Host *'; 968push @cfgarr, '#'; 969push @cfgarr, "Port $port"; 970push @cfgarr, "HostName $listenaddr"; 971push @cfgarr, "User $username"; 972push @cfgarr, 'Protocol 2'; 973push @cfgarr, '#'; 974 975# BindAddress option is not supported by OpenSSH for Windows 976if (!($sshdid =~ /OpenSSH-Windows/)) { 977 push @cfgarr, "BindAddress $listenaddr"; 978} 979 980push @cfgarr, '#'; 981push @cfgarr, "IdentityFile $identity_config"; 982push @cfgarr, "UserKnownHostsFile $knownhosts_config"; 983push @cfgarr, '#'; 984push @cfgarr, 'BatchMode yes'; 985push @cfgarr, 'ChallengeResponseAuthentication no'; 986push @cfgarr, 'CheckHostIP no'; 987push @cfgarr, 'ClearAllForwardings no'; 988push @cfgarr, 'Compression no'; 989push @cfgarr, 'ConnectionAttempts 3'; 990push @cfgarr, 'ForwardAgent no'; 991push @cfgarr, 'ForwardX11 no'; 992push @cfgarr, 'GatewayPorts no'; 993push @cfgarr, 'GlobalKnownHostsFile /dev/null'; 994push @cfgarr, 'HostbasedAuthentication no'; 995push @cfgarr, 'KbdInteractiveAuthentication no'; 996push @cfgarr, "LogLevel $loglevel"; 997push @cfgarr, 'NumberOfPasswordPrompts 0'; 998push @cfgarr, 'PasswordAuthentication no'; 999push @cfgarr, 'PreferredAuthentications publickey'; 1000push @cfgarr, 'PubkeyAuthentication yes'; 1001 1002# RSA authentication options are not supported by OpenSSH for Windows 1003if (!($sshdid =~ /OpenSSH-Windows/ || pathhelp::os_is_win())) { 1004 push @cfgarr, 'RhostsRSAAuthentication no'; 1005 push @cfgarr, 'RSAAuthentication no'; 1006} 1007 1008# Disabled StrictHostKeyChecking since it makes the tests fail on my 1009# OpenSSH_6.0p1 on Debian Linux / Daniel 1010push @cfgarr, 'StrictHostKeyChecking no'; 1011push @cfgarr, 'UsePrivilegedPort no'; 1012push @cfgarr, '#'; 1013 1014 1015#*************************************************************************** 1016# Options supported in ssh client newer than OpenSSH 2.9.9 1017# 1018 1019if(($sshid =~ /OpenSSH/) && ($sshvernum >= 370)) { 1020 push @cfgarr, 'AddressFamily any'; 1021} 1022 1023if((($sshid =~ /OpenSSH/) && ($sshvernum >= 370)) || 1024 (($sshid =~ /SunSSH/) && ($sshvernum >= 120))) { 1025 push @cfgarr, 'ConnectTimeout 30'; 1026} 1027 1028if(($sshid =~ /OpenSSH/) && ($sshvernum >= 390)) { 1029 push @cfgarr, 'ControlMaster no'; 1030} 1031 1032if(($sshid =~ /OpenSSH/) && ($sshvernum >= 420)) { 1033 push @cfgarr, 'ControlPath none'; 1034} 1035 1036if(($sshid =~ /SunSSH/) && ($sshvernum >= 120)) { 1037 push @cfgarr, 'DisableBanner yes'; 1038} 1039 1040if(($sshid =~ /OpenSSH/) && ($sshvernum >= 360)) { 1041 push @cfgarr, 'EnableSSHKeysign no'; 1042} 1043 1044if(($sshid =~ /OpenSSH/) && ($sshvernum >= 440)) { 1045 push @cfgarr, 'ExitOnForwardFailure yes'; 1046} 1047 1048if((($sshid =~ /OpenSSH/) && ($sshvernum >= 380)) || 1049 (($sshid =~ /SunSSH/) && ($sshvernum >= 120))) { 1050 push @cfgarr, 'ForwardX11Trusted no'; 1051} 1052 1053if(($sshd_builtwith_GSSAPI) && ($sshdid eq $sshid) && 1054 ($sshdvernum == $sshvernum)) { 1055 push @cfgarr, 'GSSAPIAuthentication no'; 1056 push @cfgarr, 'GSSAPIDelegateCredentials no'; 1057 if($sshid =~ /SunSSH/) { 1058 push @cfgarr, 'GSSAPIKeyExchange no'; 1059 } 1060} 1061 1062if((($sshid =~ /OpenSSH/) && ($sshvernum >= 400)) || 1063 (($sshid =~ /SunSSH/) && ($sshvernum >= 120))) { 1064 push @cfgarr, 'HashKnownHosts no'; 1065} 1066 1067if(($sshid =~ /OpenSSH/) && ($sshvernum >= 390)) { 1068 push @cfgarr, 'IdentitiesOnly yes'; 1069} 1070 1071if(($sshid =~ /SunSSH/) && ($sshvernum >= 120)) { 1072 push @cfgarr, 'IgnoreIfUnknown no'; 1073} 1074 1075if((($sshid =~ /OpenSSH/) && ($sshvernum < 380)) || 1076 ($sshid =~ /SunSSH/)) { 1077 push @cfgarr, 'KeepAlive no'; 1078} 1079 1080if((($sshid =~ /OpenSSH/) && ($sshvernum >= 300)) || 1081 ($sshid =~ /SunSSH/)) { 1082 push @cfgarr, 'NoHostAuthenticationForLocalhost no'; 1083} 1084 1085if(($sshid =~ /OpenSSH/) && ($sshvernum >= 430)) { 1086 push @cfgarr, 'PermitLocalCommand no'; 1087} 1088 1089if((($sshid =~ /OpenSSH/) && ($sshvernum >= 370)) || 1090 (($sshid =~ /SunSSH/) && ($sshvernum >= 120))) { 1091 push @cfgarr, 'RekeyLimit 1G'; 1092} 1093 1094if((($sshid =~ /OpenSSH/) && ($sshvernum >= 380)) || 1095 (($sshid =~ /SunSSH/) && ($sshvernum >= 120))) { 1096 push @cfgarr, 'ServerAliveCountMax 3'; 1097 push @cfgarr, 'ServerAliveInterval 0'; 1098} 1099 1100if(($sshid =~ /OpenSSH/) && ($sshvernum >= 380)) { 1101 push @cfgarr, 'TCPKeepAlive no'; 1102} 1103 1104if(($sshid =~ /OpenSSH/) && ($sshvernum >= 430)) { 1105 push @cfgarr, 'Tunnel no'; 1106} 1107 1108if(($sshid =~ /OpenSSH/) && ($sshvernum >= 380)) { 1109 push @cfgarr, 'VerifyHostKeyDNS no'; 1110} 1111 1112push @cfgarr, '#'; 1113 1114 1115#*************************************************************************** 1116# Write out resulting ssh client configuration file for curl's tests 1117# 1118$error = dump_array($sshconfig, @cfgarr); 1119if($error) { 1120 logmsg "$error\n"; 1121 exit 1; 1122} 1123 1124 1125#*************************************************************************** 1126# Initialize client sftp config with options actually supported. 1127# 1128logmsg "generating sftp client config file...\n" if($verbose); 1129splice @cfgarr, 1, 1, "# $sshverstr sftp client configuration file for curl testing"; 1130# 1131for(my $i = scalar(@cfgarr) - 1; $i > 0; $i--) { 1132 if($cfgarr[$i] =~ /^DynamicForward/) { 1133 splice @cfgarr, $i, 1; 1134 next; 1135 } 1136 if($cfgarr[$i] =~ /^ClearAllForwardings/) { 1137 splice @cfgarr, $i, 1, "ClearAllForwardings yes"; 1138 next; 1139 } 1140} 1141 1142 1143#*************************************************************************** 1144# Write out resulting sftp client configuration file for curl's tests 1145# 1146$error = dump_array($sftpconfig, @cfgarr); 1147if($error) { 1148 logmsg "$error\n"; 1149 exit 1; 1150} 1151@cfgarr = (); 1152 1153 1154#*************************************************************************** 1155# Generate client sftp commands batch file for sftp server verification 1156# 1157logmsg "generating sftp client commands file...\n" if($verbose); 1158push @cfgarr, 'pwd'; 1159push @cfgarr, 'quit'; 1160$error = dump_array(pp($sftpcmds), @cfgarr); 1161if($error) { 1162 logmsg "$error\n"; 1163 exit 1; 1164} 1165@cfgarr = (); 1166 1167#*************************************************************************** 1168# Prepare command line of ssh server daemon 1169# 1170my $cmd = "\"$sshd\" -e -D -f $sshdconfig_abs > $sshdlog 2>&1"; 1171logmsg "SCP/SFTP server listening on port $port\n" if($verbose); 1172logmsg "RUN: $cmd\n" if($verbose); 1173 1174#*************************************************************************** 1175# Start the ssh server daemon on Windows without forking it 1176# 1177if ($sshdid =~ /OpenSSH-Windows/) { 1178 # Fake pidfile for ssh server on Windows. 1179 if(open(my $out, ">", "$pidfile")) { 1180 print $out $$ . "\n"; 1181 close($out); 1182 } 1183 1184 # Flush output. 1185 $| = 1; 1186 1187 # Put an "exec" in front of the command so that the child process 1188 # keeps this child's process ID by being tied to the spawned shell. 1189 exec("exec $cmd") || die "Can't exec() $cmd: $!"; 1190 # exec() will create a new process, but ties the existence of the 1191 # new process to the parent waiting perl.exe and sh.exe processes. 1192 1193 # exec() should never return back here to this process. We protect 1194 # ourselves by calling die() just in case something goes really bad. 1195 die "error: exec() has returned"; 1196} 1197 1198#*************************************************************************** 1199# Start the ssh server daemon without forking it 1200# 1201# "exec" avoids the shell process sticking around 1202my $rc = system("exec " . $cmd); 1203if($rc == -1) { 1204 logmsg "\"$sshd\" failed with: $!\n"; 1205} 1206elsif($rc & 127) { 1207 logmsg sprintf("\"$sshd\" died with signal %d, and %s coredump\n", 1208 ($rc & 127), ($rc & 128)?'a':'no'); 1209} 1210elsif($verbose && ($rc >> 8)) { 1211 logmsg sprintf("\"$sshd\" exited with %d\n", $rc >> 8); 1212} 1213 1214 1215#*************************************************************************** 1216# Clean up once the server has stopped 1217# 1218unlink(pp($hstprvkeyf), pp($hstpubkeyf), pp($hstpubmd5f), pp($hstpubsha256f), 1219 pp($cliprvkeyf), pp($clipubkeyf), pp($knownhosts), 1220 $sshdconfig, $sshconfig, $sftpconfig); 1221 1222exit 0; 1223