2
0

sshhelp.pm 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. #***************************************************************************
  2. # _ _ ____ _
  3. # Project ___| | | | _ \| |
  4. # / __| | | | |_) | |
  5. # | (__| |_| | _ <| |___
  6. # \___|\___/|_| \_\_____|
  7. #
  8. # Copyright (C) 1998 - 2022, 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. use Exporter;
  28. use File::Spec;
  29. #***************************************************************************
  30. # Global symbols allowed without explicit package name
  31. #
  32. use vars qw(
  33. @ISA
  34. @EXPORT_OK
  35. $sshdexe
  36. $sshexe
  37. $sftpsrvexe
  38. $sftpexe
  39. $sshkeygenexe
  40. $httptlssrvexe
  41. $sshdconfig
  42. $sshconfig
  43. $sftpconfig
  44. $knownhosts
  45. $sshdlog
  46. $sshlog
  47. $sftplog
  48. $sftpcmds
  49. $hstprvkeyf
  50. $hstpubkeyf
  51. $hstpubmd5f
  52. $hstpubsha256f
  53. $cliprvkeyf
  54. $clipubkeyf
  55. @sftppath
  56. @httptlssrvpath
  57. );
  58. #***************************************************************************
  59. # Inherit Exporter's capabilities
  60. #
  61. @ISA = qw(Exporter);
  62. #***************************************************************************
  63. # Global symbols this module will export upon request
  64. #
  65. @EXPORT_OK = qw(
  66. $sshdexe
  67. $sshexe
  68. $sftpsrvexe
  69. $sftpexe
  70. $sshkeygenexe
  71. $sshdconfig
  72. $sshconfig
  73. $sftpconfig
  74. $knownhosts
  75. $sshdlog
  76. $sshlog
  77. $sftplog
  78. $sftpcmds
  79. $hstprvkeyf
  80. $hstpubkeyf
  81. $hstpubmd5f
  82. $hstpubsha256f
  83. $cliprvkeyf
  84. $clipubkeyf
  85. display_sshdconfig
  86. display_sshconfig
  87. display_sftpconfig
  88. display_sshdlog
  89. display_sshlog
  90. display_sftplog
  91. dump_array
  92. exe_ext
  93. find_sshd
  94. find_ssh
  95. find_sftpsrv
  96. find_sftp
  97. find_sshkeygen
  98. find_httptlssrv
  99. logmsg
  100. sshversioninfo
  101. );
  102. #***************************************************************************
  103. # Global variables initialization
  104. #
  105. $sshdexe = 'sshd' .exe_ext('SSH'); # base name and ext of ssh daemon
  106. $sshexe = 'ssh' .exe_ext('SSH'); # base name and ext of ssh client
  107. $sftpsrvexe = 'sftp-server' .exe_ext('SSH'); # base name and ext of sftp-server
  108. $sftpexe = 'sftp' .exe_ext('SSH'); # base name and ext of sftp client
  109. $sshkeygenexe = 'ssh-keygen' .exe_ext('SSH'); # base name and ext of ssh-keygen
  110. $httptlssrvexe = 'gnutls-serv' .exe_ext('SSH'); # base name and ext of gnutls-serv
  111. $sshdconfig = 'curl_sshd_config'; # ssh daemon config file
  112. $sshconfig = 'curl_ssh_config'; # ssh client config file
  113. $sftpconfig = 'curl_sftp_config'; # sftp client config file
  114. $sshdlog = undef; # ssh daemon log file
  115. $sshlog = undef; # ssh client log file
  116. $sftplog = undef; # sftp client log file
  117. $sftpcmds = 'curl_sftp_cmds'; # sftp client commands batch file
  118. $knownhosts = 'curl_client_knownhosts'; # ssh knownhosts file
  119. $hstprvkeyf = 'curl_host_rsa_key'; # host private key file
  120. $hstpubkeyf = 'curl_host_rsa_key.pub'; # host public key file
  121. $hstpubmd5f = 'curl_host_rsa_key.pub_md5'; # md5 hash of host public key
  122. $hstpubsha256f = 'curl_host_rsa_key.pub_sha256'; # sha256 hash of host public key
  123. $cliprvkeyf = 'curl_client_key'; # client private key file
  124. $clipubkeyf = 'curl_client_key.pub'; # client public key file
  125. #***************************************************************************
  126. # Absolute paths where to look for sftp-server plugin, when not in PATH
  127. #
  128. @sftppath = qw(
  129. /usr/lib/openssh
  130. /usr/libexec/openssh
  131. /usr/libexec
  132. /usr/local/libexec
  133. /opt/local/libexec
  134. /usr/lib/ssh
  135. /usr/libexec/ssh
  136. /usr/sbin
  137. /usr/lib
  138. /usr/lib/ssh/openssh
  139. /usr/lib64/ssh
  140. /usr/lib64/misc
  141. /usr/lib/misc
  142. /usr/local/sbin
  143. /usr/freeware/bin
  144. /usr/freeware/sbin
  145. /usr/freeware/libexec
  146. /opt/ssh/sbin
  147. /opt/ssh/libexec
  148. );
  149. #***************************************************************************
  150. # Absolute paths where to look for httptlssrv (gnutls-serv), when not in PATH
  151. #
  152. @httptlssrvpath = qw(
  153. /usr/sbin
  154. /usr/libexec
  155. /usr/lib
  156. /usr/lib/misc
  157. /usr/lib64/misc
  158. /usr/local/bin
  159. /usr/local/sbin
  160. /usr/local/libexec
  161. /opt/local/bin
  162. /opt/local/sbin
  163. /opt/local/libexec
  164. /usr/freeware/bin
  165. /usr/freeware/sbin
  166. /usr/freeware/libexec
  167. /opt/gnutls/bin
  168. /opt/gnutls/sbin
  169. /opt/gnutls/libexec
  170. );
  171. #***************************************************************************
  172. # Return file extension for executable files on this operating system
  173. #
  174. sub exe_ext {
  175. my ($component, @arr) = @_;
  176. if ($ENV{'CURL_TEST_EXE_EXT'}) {
  177. return $ENV{'CURL_TEST_EXE_EXT'};
  178. }
  179. if ($ENV{'CURL_TEST_EXE_EXT_'.$component}) {
  180. return $ENV{'CURL_TEST_EXE_EXT_'.$component};
  181. }
  182. if ($^O eq 'MSWin32' || $^O eq 'cygwin' || $^O eq 'msys' ||
  183. $^O eq 'dos' || $^O eq 'os2') {
  184. return '.exe';
  185. }
  186. }
  187. #***************************************************************************
  188. # Create or overwrite the given file with lines from an array of strings
  189. #
  190. sub dump_array {
  191. my ($filename, @arr) = @_;
  192. my $error;
  193. if(!$filename) {
  194. $error = 'Error: Missing argument 1 for dump_array()';
  195. }
  196. elsif(open(TEXTFH, ">$filename")) {
  197. foreach my $line (@arr) {
  198. $line .= "\n" unless($line =~ /\n$/);
  199. print TEXTFH $line;
  200. }
  201. if(!close(TEXTFH)) {
  202. $error = "Error: cannot close file $filename";
  203. }
  204. }
  205. else {
  206. $error = "Error: cannot write file $filename";
  207. }
  208. return $error;
  209. }
  210. #***************************************************************************
  211. # Display a message
  212. #
  213. sub logmsg {
  214. my ($line) = @_;
  215. chomp $line if($line);
  216. $line .= "\n";
  217. print "$line";
  218. }
  219. #***************************************************************************
  220. # Display contents of the given file
  221. #
  222. sub display_file {
  223. my $filename = $_[0];
  224. print "=== Start of file $filename\n";
  225. if(open(DISPLAYFH, "<$filename")) {
  226. while(my $line = <DISPLAYFH>) {
  227. print "$line";
  228. }
  229. close DISPLAYFH;
  230. }
  231. print "=== End of file $filename\n";
  232. }
  233. #***************************************************************************
  234. # Display contents of the ssh daemon config file
  235. #
  236. sub display_sshdconfig {
  237. display_file($sshdconfig);
  238. }
  239. #***************************************************************************
  240. # Display contents of the ssh client config file
  241. #
  242. sub display_sshconfig {
  243. display_file($sshconfig);
  244. }
  245. #***************************************************************************
  246. # Display contents of the sftp client config file
  247. #
  248. sub display_sftpconfig {
  249. display_file($sftpconfig);
  250. }
  251. #***************************************************************************
  252. # Display contents of the ssh daemon log file
  253. #
  254. sub display_sshdlog {
  255. die "error: \$sshdlog uninitialized" if(not defined $sshdlog);
  256. display_file($sshdlog);
  257. }
  258. #***************************************************************************
  259. # Display contents of the ssh client log file
  260. #
  261. sub display_sshlog {
  262. die "error: \$sshlog uninitialized" if(not defined $sshlog);
  263. display_file($sshlog);
  264. }
  265. #***************************************************************************
  266. # Display contents of the sftp client log file
  267. #
  268. sub display_sftplog {
  269. die "error: \$sftplog uninitialized" if(not defined $sftplog);
  270. display_file($sftplog);
  271. }
  272. #***************************************************************************
  273. # Find a file somewhere in the given path
  274. #
  275. sub find_file {
  276. my $fn = $_[0];
  277. shift;
  278. my @path = @_;
  279. foreach (@path) {
  280. my $file = File::Spec->catfile($_, $fn);
  281. if(-e $file && ! -d $file) {
  282. return $file;
  283. }
  284. }
  285. }
  286. #***************************************************************************
  287. # Find an executable file somewhere in the given path
  288. #
  289. sub find_exe_file {
  290. my $fn = $_[0];
  291. shift;
  292. my @path = @_;
  293. my $xext = exe_ext('SSH');
  294. foreach (@path) {
  295. my $file = File::Spec->catfile($_, $fn);
  296. if(-e $file && ! -d $file) {
  297. return $file if(-x $file);
  298. return $file if(($xext) && (lc($file) =~ /\Q$xext\E$/));
  299. }
  300. }
  301. }
  302. #***************************************************************************
  303. # Find a file in environment path or in our sftppath
  304. #
  305. sub find_file_spath {
  306. my $filename = $_[0];
  307. my @spath;
  308. push(@spath, File::Spec->path());
  309. push(@spath, @sftppath);
  310. return find_file($filename, @spath);
  311. }
  312. #***************************************************************************
  313. # Find an executable file in environment path or in our httptlssrvpath
  314. #
  315. sub find_exe_file_hpath {
  316. my $filename = $_[0];
  317. my @hpath;
  318. push(@hpath, File::Spec->path());
  319. push(@hpath, @httptlssrvpath);
  320. return find_exe_file($filename, @hpath);
  321. }
  322. #***************************************************************************
  323. # Find ssh daemon and return canonical filename
  324. #
  325. sub find_sshd {
  326. return find_file_spath($sshdexe);
  327. }
  328. #***************************************************************************
  329. # Find ssh client and return canonical filename
  330. #
  331. sub find_ssh {
  332. return find_file_spath($sshexe);
  333. }
  334. #***************************************************************************
  335. # Find sftp-server plugin and return canonical filename
  336. #
  337. sub find_sftpsrv {
  338. return find_file_spath($sftpsrvexe);
  339. }
  340. #***************************************************************************
  341. # Find sftp client and return canonical filename
  342. #
  343. sub find_sftp {
  344. return find_file_spath($sftpexe);
  345. }
  346. #***************************************************************************
  347. # Find ssh-keygen and return canonical filename
  348. #
  349. sub find_sshkeygen {
  350. return find_file_spath($sshkeygenexe);
  351. }
  352. #***************************************************************************
  353. # Find httptlssrv (gnutls-serv) and return canonical filename
  354. #
  355. sub find_httptlssrv {
  356. return find_exe_file_hpath($httptlssrvexe);
  357. }
  358. #***************************************************************************
  359. # Return version info for the given ssh client or server binaries
  360. #
  361. sub sshversioninfo {
  362. my $sshbin = $_[0]; # canonical filename
  363. my $major;
  364. my $minor;
  365. my $patch;
  366. my $sshid;
  367. my $versnum;
  368. my $versstr;
  369. my $error;
  370. if(!$sshbin) {
  371. $error = 'Error: Missing argument 1 for sshversioninfo()';
  372. }
  373. elsif(! -x $sshbin) {
  374. $error = "Error: cannot read or execute $sshbin";
  375. }
  376. else {
  377. my $cmd = ($sshbin =~ /$sshdexe$/) ? "\"$sshbin\" -?" : "\"$sshbin\" -V";
  378. $error = "$cmd\n";
  379. foreach my $tmpstr (qx($cmd 2>&1)) {
  380. if($tmpstr =~ /OpenSSH[_-](\d+)\.(\d+)(\.(\d+))*/i) {
  381. $major = $1;
  382. $minor = $2;
  383. $patch = $4?$4:0;
  384. $sshid = 'OpenSSH';
  385. $versnum = (100*$major) + (10*$minor) + $patch;
  386. $versstr = "$sshid $major.$minor.$patch";
  387. $error = undef;
  388. last;
  389. }
  390. if($tmpstr =~ /OpenSSH[_-]for[_-]Windows[_-](\d+)\.(\d+)(\.(\d+))*/i) {
  391. $major = $1;
  392. $minor = $2;
  393. $patch = $4?$4:0;
  394. $sshid = 'OpenSSH-Windows';
  395. $versnum = (100*$major) + (10*$minor) + $patch;
  396. $versstr = "$sshid $major.$minor.$patch";
  397. $error = undef;
  398. last;
  399. }
  400. if($tmpstr =~ /Sun[_-]SSH[_-](\d+)\.(\d+)(\.(\d+))*/i) {
  401. $major = $1;
  402. $minor = $2;
  403. $patch = $4?$4:0;
  404. $sshid = 'SunSSH';
  405. $versnum = (100*$major) + (10*$minor) + $patch;
  406. $versstr = "$sshid $major.$minor.$patch";
  407. $error = undef;
  408. last;
  409. }
  410. $error .= $tmpstr;
  411. }
  412. chomp $error if($error);
  413. }
  414. return ($sshid, $versnum, $versstr, $error);
  415. }
  416. #***************************************************************************
  417. # End of library
  418. 1;