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