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