sshhelp.pm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. #***************************************************************************
  2. # _ _ ____ _
  3. # Project ___| | | | _ \| |
  4. # / __| | | | |_) | |
  5. # | (__| |_| | _ <| |___
  6. # \___|\___/|_| \_\_____|
  7. #
  8. # Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  9. #
  10. # This software is licensed as described in the file COPYING, which
  11. # you should have received as part of this distribution. The terms
  12. # are also available at https://curl.se/docs/copyright.html.
  13. #
  14. # You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. # copies of the Software, and permit persons to whom the Software is
  16. # furnished to do so, under the terms of the COPYING file.
  17. #
  18. # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. # KIND, either express or implied.
  20. #
  21. # SPDX-License-Identifier: curl
  22. #
  23. #***************************************************************************
  24. package sshhelp;
  25. use strict;
  26. use warnings;
  27. BEGIN {
  28. use base qw(Exporter);
  29. our @EXPORT_OK = qw(
  30. $sshdexe
  31. $sshexe
  32. $sftpsrvexe
  33. $sftpexe
  34. $sshkeygenexe
  35. $sshdconfig
  36. $sshconfig
  37. $sftpconfig
  38. $knownhosts
  39. $sshdlog
  40. $sshlog
  41. $sftplog
  42. $sftpcmds
  43. $hstprvkeyf
  44. $hstpubkeyf
  45. $hstpubmd5f
  46. $hstpubsha256f
  47. $cliprvkeyf
  48. $clipubkeyf
  49. display_sshdconfig
  50. display_sshconfig
  51. display_sftpconfig
  52. display_sshdlog
  53. display_sshlog
  54. display_sftplog
  55. dump_array
  56. find_sshd
  57. find_ssh
  58. find_sftpsrv
  59. find_sftp
  60. find_sshkeygen
  61. find_httptlssrv
  62. logmsg
  63. sshversioninfo
  64. );
  65. }
  66. use File::Spec;
  67. use pathhelp qw(
  68. exe_ext
  69. );
  70. #***************************************************************************
  71. # Global variables initialization
  72. #
  73. our $sshdexe = 'sshd' .exe_ext('SSH'); # base name and ext of ssh daemon
  74. our $sshexe = 'ssh' .exe_ext('SSH'); # base name and ext of ssh client
  75. our $sftpsrvexe = 'sftp-server' .exe_ext('SSH'); # base name and ext of sftp-server
  76. our $sftpexe = 'sftp' .exe_ext('SSH'); # base name and ext of sftp client
  77. our $sshkeygenexe = 'ssh-keygen' .exe_ext('SSH'); # base name and ext of ssh-keygen
  78. our $httptlssrvexe = 'gnutls-serv' .exe_ext('SSH'); # base name and ext of gnutls-serv
  79. our $sshdconfig = 'curl_sshd_config'; # ssh daemon config file
  80. our $sshconfig = 'curl_ssh_config'; # ssh client config file
  81. our $sftpconfig = 'curl_sftp_config'; # sftp client config file
  82. our $sshdlog = undef; # ssh daemon log file
  83. our $sshlog = undef; # ssh client log file
  84. our $sftplog = undef; # sftp client log file
  85. our $sftpcmds = 'curl_sftp_cmds'; # sftp client commands batch file
  86. our $knownhosts = 'curl_client_knownhosts'; # ssh knownhosts file
  87. our $hstprvkeyf = 'curl_host_rsa_key'; # host private key file
  88. our $hstpubkeyf = 'curl_host_rsa_key.pub'; # host public key file
  89. our $hstpubmd5f = 'curl_host_rsa_key.pub_md5'; # md5 hash of host public key
  90. our $hstpubsha256f = 'curl_host_rsa_key.pub_sha256'; # sha256 hash of host public key
  91. our $cliprvkeyf = 'curl_client_key'; # client private key file
  92. our $clipubkeyf = 'curl_client_key.pub'; # client public key file
  93. #***************************************************************************
  94. # Absolute paths where to look for sftp-server plugin, when not in PATH
  95. #
  96. our @sftppath = qw(
  97. /usr/lib/openssh
  98. /usr/libexec/openssh
  99. /usr/libexec
  100. /usr/local/libexec
  101. /opt/local/libexec
  102. /usr/lib/ssh
  103. /usr/libexec/ssh
  104. /usr/sbin
  105. /usr/lib
  106. /usr/lib/ssh/openssh
  107. /usr/lib64/ssh
  108. /usr/lib64/misc
  109. /usr/lib/misc
  110. /usr/local/sbin
  111. /usr/freeware/bin
  112. /usr/freeware/sbin
  113. /usr/freeware/libexec
  114. /opt/ssh/sbin
  115. /opt/ssh/libexec
  116. );
  117. #***************************************************************************
  118. # Absolute paths where to look for httptlssrv (gnutls-serv), when not in PATH
  119. #
  120. our @httptlssrvpath = qw(
  121. /usr/sbin
  122. /usr/libexec
  123. /usr/lib
  124. /usr/lib/misc
  125. /usr/lib64/misc
  126. /usr/local/bin
  127. /usr/local/sbin
  128. /usr/local/libexec
  129. /opt/local/bin
  130. /opt/local/sbin
  131. /opt/local/libexec
  132. /usr/freeware/bin
  133. /usr/freeware/sbin
  134. /usr/freeware/libexec
  135. /opt/gnutls/bin
  136. /opt/gnutls/sbin
  137. /opt/gnutls/libexec
  138. );
  139. #***************************************************************************
  140. # Create or overwrite the given file with lines from an array of strings
  141. #
  142. sub dump_array {
  143. my ($filename, @arr) = @_;
  144. my $error;
  145. if(!$filename) {
  146. $error = 'Error: Missing argument 1 for dump_array()';
  147. }
  148. elsif(open(my $textfh, ">", $filename)) {
  149. foreach my $line (@arr) {
  150. $line .= "\n" if($line !~ /\n$/);
  151. print $textfh $line;
  152. }
  153. if(!close($textfh)) {
  154. $error = "Error: cannot close file $filename";
  155. }
  156. }
  157. else {
  158. $error = "Error: cannot write file $filename";
  159. }
  160. return $error;
  161. }
  162. #***************************************************************************
  163. # Display a message
  164. #
  165. sub logmsg {
  166. my ($line) = @_;
  167. chomp $line if($line);
  168. $line .= "\n";
  169. print "$line";
  170. }
  171. #***************************************************************************
  172. # Display contents of the given file
  173. #
  174. sub display_file {
  175. my $filename = $_[0];
  176. print "=== Start of file $filename\n";
  177. if(open(my $displayfh, "<", "$filename")) {
  178. while(my $line = <$displayfh>) {
  179. print "$line";
  180. }
  181. close $displayfh;
  182. }
  183. print "=== End of file $filename\n";
  184. }
  185. #***************************************************************************
  186. # Display contents of the ssh daemon config file
  187. #
  188. sub display_sshdconfig {
  189. display_file($sshdconfig);
  190. }
  191. #***************************************************************************
  192. # Display contents of the ssh client config file
  193. #
  194. sub display_sshconfig {
  195. display_file($sshconfig);
  196. }
  197. #***************************************************************************
  198. # Display contents of the sftp client config file
  199. #
  200. sub display_sftpconfig {
  201. display_file($sftpconfig);
  202. }
  203. #***************************************************************************
  204. # Display contents of the ssh daemon log file
  205. #
  206. sub display_sshdlog {
  207. die "error: \$sshdlog uninitialized" if(not defined $sshdlog);
  208. display_file($sshdlog);
  209. }
  210. #***************************************************************************
  211. # Display contents of the ssh client log file
  212. #
  213. sub display_sshlog {
  214. die "error: \$sshlog uninitialized" if(not defined $sshlog);
  215. display_file($sshlog);
  216. }
  217. #***************************************************************************
  218. # Display contents of the sftp client log file
  219. #
  220. sub display_sftplog {
  221. die "error: \$sftplog uninitialized" if(not defined $sftplog);
  222. display_file($sftplog);
  223. }
  224. #***************************************************************************
  225. # Find a file somewhere in the given path
  226. #
  227. sub find_file {
  228. my $fn = $_[0];
  229. shift;
  230. my @path = @_;
  231. foreach (@path) {
  232. my $file = File::Spec->catfile($_, $fn);
  233. if(-e $file && ! -d $file) {
  234. return $file;
  235. }
  236. }
  237. return "";
  238. }
  239. #***************************************************************************
  240. # Find an executable file somewhere in the given path
  241. #
  242. sub find_exe_file {
  243. my $fn = $_[0];
  244. shift;
  245. my @path = @_;
  246. my $xext = exe_ext('SSH');
  247. foreach (@path) {
  248. my $file = File::Spec->catfile($_, $fn);
  249. if(-e $file && ! -d $file) {
  250. return $file if(-x $file);
  251. return $file if(($xext) && (lc($file) =~ /\Q$xext\E$/));
  252. }
  253. }
  254. return "";
  255. }
  256. #***************************************************************************
  257. # Find a file in environment path or in our sftppath
  258. #
  259. sub find_file_spath {
  260. my $filename = $_[0];
  261. my @spath;
  262. push(@spath, File::Spec->path());
  263. push(@spath, @sftppath);
  264. return find_file($filename, @spath);
  265. }
  266. #***************************************************************************
  267. # Find an executable file in environment path or in our httptlssrvpath
  268. #
  269. sub find_exe_file_hpath {
  270. my $filename = $_[0];
  271. my @hpath;
  272. push(@hpath, File::Spec->path());
  273. push(@hpath, @httptlssrvpath);
  274. return find_exe_file($filename, @hpath);
  275. }
  276. #***************************************************************************
  277. # Find ssh daemon and return canonical filename
  278. #
  279. sub find_sshd {
  280. return find_file_spath($sshdexe);
  281. }
  282. #***************************************************************************
  283. # Find ssh client and return canonical filename
  284. #
  285. sub find_ssh {
  286. return find_file_spath($sshexe);
  287. }
  288. #***************************************************************************
  289. # Find sftp-server plugin and return canonical filename
  290. #
  291. sub find_sftpsrv {
  292. return find_file_spath($sftpsrvexe);
  293. }
  294. #***************************************************************************
  295. # Find sftp client and return canonical filename
  296. #
  297. sub find_sftp {
  298. return find_file_spath($sftpexe);
  299. }
  300. #***************************************************************************
  301. # Find ssh-keygen and return canonical filename
  302. #
  303. sub find_sshkeygen {
  304. return find_file_spath($sshkeygenexe);
  305. }
  306. #***************************************************************************
  307. # Find httptlssrv (gnutls-serv) and return canonical filename
  308. #
  309. sub find_httptlssrv {
  310. my $p = find_exe_file_hpath($httptlssrvexe);
  311. if($p) {
  312. my @o = `"$p" -l`;
  313. my $found;
  314. for(@o) {
  315. if(/Key exchange: SRP/) {
  316. $found = 1;
  317. last;
  318. }
  319. }
  320. return $p if($found);
  321. }
  322. return "";
  323. }
  324. #***************************************************************************
  325. # Return version info for the given ssh client or server binaries
  326. #
  327. sub sshversioninfo {
  328. my $sshbin = $_[0]; # canonical filename
  329. my $major;
  330. my $minor;
  331. my $patch;
  332. my $sshid;
  333. my $versnum;
  334. my $versstr;
  335. my $error;
  336. if(!$sshbin) {
  337. $error = 'Error: Missing argument 1 for sshversioninfo()';
  338. }
  339. elsif(! -x $sshbin) {
  340. $error = "Error: cannot read or execute $sshbin";
  341. }
  342. else {
  343. my $cmd = ($sshbin =~ /$sshdexe$/) ? "\"$sshbin\" -?" : "\"$sshbin\" -V";
  344. $error = "$cmd\n";
  345. foreach my $tmpstr (qx($cmd 2>&1)) {
  346. if($tmpstr =~ /OpenSSH[_-](\d+)\.(\d+)(\.(\d+))*/i) {
  347. $major = $1;
  348. $minor = $2;
  349. $patch = $4?$4:0;
  350. $sshid = 'OpenSSH';
  351. $versnum = (100*$major) + (10*$minor) + $patch;
  352. $versstr = "$sshid $major.$minor.$patch";
  353. $error = undef;
  354. last;
  355. }
  356. if($tmpstr =~ /OpenSSH[_-]for[_-]Windows[_-](\d+)\.(\d+)(\.(\d+))*/i) {
  357. $major = $1;
  358. $minor = $2;
  359. $patch = $4?$4:0;
  360. $sshid = 'OpenSSH-Windows';
  361. $versnum = (100*$major) + (10*$minor) + $patch;
  362. $versstr = "$sshid $major.$minor.$patch";
  363. $error = undef;
  364. last;
  365. }
  366. if($tmpstr =~ /Sun[_-]SSH[_-](\d+)\.(\d+)(\.(\d+))*/i) {
  367. $major = $1;
  368. $minor = $2;
  369. $patch = $4?$4:0;
  370. $sshid = 'SunSSH';
  371. $versnum = (100*$major) + (10*$minor) + $patch;
  372. $versstr = "$sshid $major.$minor.$patch";
  373. $error = undef;
  374. last;
  375. }
  376. $error .= $tmpstr;
  377. }
  378. chomp $error if($error);
  379. }
  380. return ($sshid, $versnum, $versstr, $error);
  381. }
  382. #***************************************************************************
  383. # End of library
  384. 1;