spell "natural" and "unsigned" in some more files
[racktables] / gateways / sshnokey
CommitLineData
cfe0e3a0
IT
1#!/usr/bin/perl
2# This file is a part of RackTables, a datacenter and server room management
3# framework. See accompanying file "COPYING" for the full copyright and
4# licensing information.
5#
6# NOTE: Logging in via ssh using a password, whilst better then doing
7# the same via telnet/netcat, is still a bad idea when your network is
8# not properly secured. If you try to login to a compromised system
9# using a password, this password is now in the hands of the attackers.
10#
11# If possible, use the public key authenticated version instead. In case
12# that is not an option, consider different passwords for every system.
13#
f1f8982a 14# To summarize, treat this as a slightly better telnet client and make
cfe0e3a0
IT
15# sure the network this runs in is secure.
16
17use strict;
18use Getopt::Long;
19use Net::Telnet;
20use Net::OpenSSH;
21
22# fetch command-line parameters
23my $op_help;
24my $op_port;
25my $op_username;
26my $op_password;
27my $op_connect_timeout = 2;
28my $op_timeout = 10;
29my $op_prompt;
30my $op_delay = 0.01;
31GetOptions (
32 'h' => \$op_help,
33 'port:i' => \$op_port,
34 'connect-timeout:i' => \$op_connect_timeout,
35 'timeout:i' => \$op_timeout,
36 'prompt-delay:f' => \$op_delay,
37 'prompt:s' => \$op_prompt,
38 'username:s' => \$op_username,
39 'password:s' => \$op_password
40);
41if ($op_help) {
42 &display_help;
43 exit;
44}
45my $op_host = $ARGV[0];
46defined $op_host or die "ERROR: please specify remote host (-h for help)";
47defined $op_prompt or die "ERROR: please specify prompt regexp (-h for help)";
48my $prompt_re = qr/$op_prompt/;
49
50sub display_help {
51 print <<END;
52OpenSSH-Hardened telnet batch client for RackTables.
53Takes commands list in standard input and gives the responses via standard output.
54Login credentials are not specially handled and should be placed as first lines of input
55Usage:
56$0 {hostname} [--port={port}] [--connect-timeout={seconds}] --prompt={regexp} [--timeout={seconds}] --username={username} --password={password} --prompt-delay={prompt_delay}
57
58port: TCP port number to connect to
59connect-timeout: timeout for giving up connecting process, seconds
60prompt: command prompt regexp for interactive telnet (auth prompts too)
61timeout: wait time for activity of remote telnet peer in seconds
62NOTE: this help may be incorrect - functionality within RackTables was tested.
63
64END
65}
66
67my $port = $op_port || 22;
68
69my $ssh = Net::OpenSSH->new(
70 $op_host,
71 'port' => $op_port,
72 'user' => $op_username,
73 'password' => $op_password
74);
75$ssh->error and
76 die "Couldn't establish SSH connection: ". $ssh->error;
77
78my ($pty, $pid) = $ssh->open2pty({stderr_to_stdout => 1})
79 or die "unable to start remote shell: " . $ssh->error;
80
81my $session = Net::Telnet->new (
82 Fhopen => $pty,
83# Host => $op_host,
84# Port => $port,
85# Timeout => $op_connect_timeout,
86 Prompt => "/$op_prompt/",
87 Telnetmode => 0,
88 Cmd_remove_mode => 1,
89 Output_record_separator => "\r"
90);
91
92#$session->cmd("term len 0");
93
94
95use IO::Select;
96my $sel = new IO::Select($session);
97
98my $buff = '';
99my $nohang_read;
100until ($session->eof) {
101 # read output from the device
102 eval {
103 $buff .= $session->get (Timeout => $nohang_read ? 0 : $op_timeout, Errmode => $nohang_read ? 'return' : 'die');
104 };
105 if ($@) {
106 # check if there is something else in <STDIN>
107 if (defined <STDIN>) {
108 die $@;
109 }
110 else {
111 last; # no more input, seems like session was closed remotely by our last command
112 }
113 }
114 $nohang_read = 0;
115 print $1 if ($buff =~ s/(.*\n)//s);
116
117 next unless ($buff =~ $prompt_re);
118 # send pending commands to the device
119 if ($op_delay and IO::Select->select ($sel, undef, undef, $op_delay)) {
120 # something is received, no prompt detection at this time
121 # set NOHANG options for next reading, cause it can be telnet control sequence
122 $nohang_read = 1;
123 }
124 elsif (defined ($_ = <STDIN>)) {
125 # replace all CR and LF symbols with single trailing LF
126 s/[\015\012]//g;
127 $session->put($_ . "\012");
128 }
129 else {
130 # no more commands in input
131 last;
132 }
133}
134print $buff;