| #*************************************************************************** | |
| # _ _ ____ _ | |
| # Project ___| | | | _ \| | | |
| # / __| | | | |_) | | | |
| # | (__| |_| | _ <| |___ | |
| # \___|\___/|_| \_\_____| | |
| # | |
| # Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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 https://curl.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. | |
| # | |
| # SPDX-License-Identifier: curl | |
| # | |
| #*************************************************************************** | |
| package sshhelp; | |
| use strict; | |
| use warnings; | |
| BEGIN { | |
| use base qw(Exporter); | |
| our @EXPORT_OK = qw( | |
| $sshdexe | |
| $sshexe | |
| $sftpsrvexe | |
| $sftpexe | |
| $sshkeygenexe | |
| $sshdconfig | |
| $sshconfig | |
| $sftpconfig | |
| $knownhosts | |
| $sshdlog | |
| $sshlog | |
| $sftplog | |
| $sftpcmds | |
| $hstprvkeyf | |
| $hstpubkeyf | |
| $hstpubmd5f | |
| $hstpubsha256f | |
| $cliprvkeyf | |
| $clipubkeyf | |
| display_sshdconfig | |
| display_sshconfig | |
| display_sftpconfig | |
| display_sshdlog | |
| display_sshlog | |
| display_sftplog | |
| dump_array | |
| find_sshd | |
| find_ssh | |
| find_sftpsrv | |
| find_sftp | |
| find_sshkeygen | |
| find_httptlssrv | |
| sshversioninfo | |
| ); | |
| } | |
| use File::Spec; | |
| use pathhelp qw( | |
| exe_ext | |
| ); | |
| #*************************************************************************** | |
| # Global variables initialization | |
| # | |
| our $sshdexe = 'sshd' .exe_ext('SSH'); # base name and ext of ssh daemon | |
| our $sshexe = 'ssh' .exe_ext('SSH'); # base name and ext of ssh client | |
| our $sftpsrvexe = 'sftp-server' .exe_ext('SSH'); # base name and ext of sftp-server | |
| our $sftpexe = 'sftp' .exe_ext('SSH'); # base name and ext of sftp client | |
| our $sshkeygenexe = 'ssh-keygen' .exe_ext('SSH'); # base name and ext of ssh-keygen | |
| our $httptlssrvexe = 'gnutls-serv' .exe_ext('SSH'); # base name and ext of gnutls-serv | |
| our $sshdconfig = 'curl_sshd_config'; # ssh daemon config file | |
| our $sshconfig = 'curl_ssh_config'; # ssh client config file | |
| our $sftpconfig = 'curl_sftp_config'; # sftp client config file | |
| our $sshdlog = undef; # ssh daemon log file | |
| our $sshlog = undef; # ssh client log file | |
| our $sftplog = undef; # sftp client log file | |
| our $sftpcmds = 'curl_sftp_cmds'; # sftp client commands batch file | |
| our $knownhosts = 'curl_client_knownhosts'; # ssh knownhosts file | |
| our $hstprvkeyf = 'curl_host_rsa_key'; # host private key file | |
| our $hstpubkeyf = 'curl_host_rsa_key.pub'; # host public key file | |
| our $hstpubmd5f = 'curl_host_rsa_key.pub_md5'; # md5 hash of host public key | |
| our $hstpubsha256f = 'curl_host_rsa_key.pub_sha256'; # sha256 hash of host public key | |
| our $cliprvkeyf = 'curl_client_key'; # client private key file | |
| our $clipubkeyf = 'curl_client_key.pub'; # client public key file | |
| #*************************************************************************** | |
| # Absolute paths where to look for sftp-server plugin, when not in PATH | |
| # | |
| our @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 | |
| /usr/freeware/sbin | |
| /usr/freeware/libexec | |
| /opt/ssh/sbin | |
| /opt/ssh/libexec | |
| ); | |
| #*************************************************************************** | |
| # Absolute paths where to look for httptlssrv (gnutls-serv), when not in PATH | |
| # | |
| our @httptlssrvpath = qw( | |
| /usr/sbin | |
| /usr/libexec | |
| /usr/lib | |
| /usr/lib/misc | |
| /usr/lib64/misc | |
| /usr/local/bin | |
| /usr/local/sbin | |
| /usr/local/libexec | |
| /opt/local/bin | |
| /opt/local/sbin | |
| /opt/local/libexec | |
| /usr/freeware/bin | |
| /usr/freeware/sbin | |
| /usr/freeware/libexec | |
| /opt/gnutls/bin | |
| /opt/gnutls/sbin | |
| /opt/gnutls/libexec | |
| ); | |
| #*************************************************************************** | |
| # 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(my $textfh, ">", $filename)) { | |
| foreach my $line (@arr) { | |
| $line .= "\n" if($line !~ /\n$/); | |
| print $textfh $line; | |
| } | |
| if(!close($textfh)) { | |
| $error = "Error: cannot close file $filename"; | |
| } | |
| } | |
| else { | |
| $error = "Error: cannot write file $filename"; | |
| } | |
| return $error; | |
| } | |
| #*************************************************************************** | |
| # Display contents of the given file | |
| # | |
| sub display_file { | |
| my $filename = $_[0]; | |
| print "=== Start of file $filename\n"; | |
| if(open(my $displayfh, "<", "$filename")) { | |
| while(my $line = <$displayfh>) { | |
| 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 sftp client config file | |
| # | |
| sub display_sftpconfig { | |
| display_file($sftpconfig); | |
| } | |
| #*************************************************************************** | |
| # Display contents of the ssh daemon log file | |
| # | |
| sub display_sshdlog { | |
| die "error: \$sshdlog uninitialized" if(not defined $sshdlog); | |
| display_file($sshdlog); | |
| } | |
| #*************************************************************************** | |
| # Display contents of the ssh client log file | |
| # | |
| sub display_sshlog { | |
| die "error: \$sshlog uninitialized" if(not defined $sshlog); | |
| display_file($sshlog); | |
| } | |
| #*************************************************************************** | |
| # Display contents of the sftp client log file | |
| # | |
| sub display_sftplog { | |
| die "error: \$sftplog uninitialized" if(not defined $sftplog); | |
| display_file($sftplog); | |
| } | |
| #*************************************************************************** | |
| # 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 && ! -d $file) { | |
| return $file; | |
| } | |
| } | |
| return ""; | |
| } | |
| #*************************************************************************** | |
| # Find an executable file somewhere in the given path | |
| # | |
| sub find_exe_file { | |
| my $fn = $_[0]; | |
| shift; | |
| my @path = @_; | |
| my $xext = exe_ext('SSH'); | |
| foreach (@path) { | |
| my $file = File::Spec->catfile($_, $fn); | |
| if(-e $file && ! -d $file) { | |
| return $file if(-x $file); | |
| return $file if(($xext) && (lc($file) =~ /\Q$xext\E$/)); | |
| } | |
| } | |
| return ""; | |
| } | |
| #*************************************************************************** | |
| # Find a file in environment path or in our sftppath | |
| # | |
| sub find_file_spath { | |
| my $filename = $_[0]; | |
| my @spath; | |
| push(@spath, File::Spec->path()); | |
| push(@spath, @sftppath); | |
| return find_file($filename, @spath); | |
| } | |
| #*************************************************************************** | |
| # Find an executable file in environment path or in our httptlssrvpath | |
| # | |
| sub find_exe_file_hpath { | |
| my $filename = $_[0]; | |
| my @hpath; | |
| push(@hpath, File::Spec->path()); | |
| push(@hpath, @httptlssrvpath); | |
| return find_exe_file($filename, @hpath); | |
| } | |
| #*************************************************************************** | |
| # Find ssh daemon and return canonical filename | |
| # | |
| sub find_sshd { | |
| return find_file_spath($sshdexe); | |
| } | |
| #*************************************************************************** | |
| # Find ssh client and return canonical filename | |
| # | |
| sub find_ssh { | |
| return find_file_spath($sshexe); | |
| } | |
| #*************************************************************************** | |
| # Find sftp-server plugin and return canonical filename | |
| # | |
| sub find_sftpsrv { | |
| return find_file_spath($sftpsrvexe); | |
| } | |
| #*************************************************************************** | |
| # Find sftp client and return canonical filename | |
| # | |
| sub find_sftp { | |
| return find_file_spath($sftpexe); | |
| } | |
| #*************************************************************************** | |
| # Find ssh-keygen and return canonical filename | |
| # | |
| sub find_sshkeygen { | |
| return find_file_spath($sshkeygenexe); | |
| } | |
| #*************************************************************************** | |
| # Find httptlssrv (gnutls-serv) and return canonical filename | |
| # | |
| sub find_httptlssrv { | |
| my $p = find_exe_file_hpath($httptlssrvexe); | |
| if($p) { | |
| my @o = `"$p" -l`; | |
| my $found; | |
| for(@o) { | |
| if(/Key exchange: SRP/) { | |
| $found = 1; | |
| last; | |
| } | |
| } | |
| return $p if($found); | |
| } | |
| return ""; | |
| } | |
| #*************************************************************************** | |
| # 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 =~ /OpenSSH[_-]for[_-]Windows[_-](\d+)\.(\d+)(\.(\d+))*/i) { | |
| $major = $1; | |
| $minor = $2; | |
| $patch = $4?$4:0; | |
| $sshid = 'OpenSSH-Windows'; | |
| $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; |