sshhelp.pm 13 KB

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