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