line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::SSH::Perl::SSH1; |
2
|
1
|
|
|
1
|
|
7
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
30
|
|
3
|
1
|
|
|
1
|
|
8
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
24
|
|
4
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
5
|
use Net::SSH::Perl::Packet; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
21
|
|
6
|
1
|
|
|
1
|
|
14
|
use Net::SSH::Perl::Buffer; |
|
1
|
|
|
|
|
10
|
|
|
1
|
|
|
|
|
29
|
|
7
|
1
|
|
|
1
|
|
5
|
use Net::SSH::Perl::Config; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
21
|
|
8
|
1
|
|
|
1
|
|
5
|
use Net::SSH::Perl::Constants qw( :protocol :msg :hosts ); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
23
|
|
9
|
1
|
|
|
1
|
|
6
|
use Net::SSH::Perl::Cipher; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
32
|
|
10
|
1
|
|
|
1
|
|
486
|
use Net::SSH::Perl::Auth; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
31
|
|
11
|
1
|
|
|
1
|
|
466
|
use Net::SSH::Perl::Comp; |
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
33
|
|
12
|
1
|
|
|
1
|
|
472
|
use Net::SSH::Perl::Key::RSA1; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
29
|
|
13
|
1
|
|
|
1
|
|
6
|
use Net::SSH::Perl::Util qw( :hosts _compute_session_id _rsa_public_encrypt ); |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
5
|
|
14
|
|
|
|
|
|
|
|
15
|
1
|
|
|
1
|
|
6
|
use Net::SSH::Perl; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
24
|
|
16
|
1
|
|
|
1
|
|
5
|
use base qw( Net::SSH::Perl ); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
100
|
|
17
|
|
|
|
|
|
|
|
18
|
1
|
|
|
1
|
|
6
|
use Math::GMP; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
4
|
|
19
|
1
|
|
|
1
|
|
23
|
use Carp qw( croak ); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
63
|
|
20
|
1
|
|
|
1
|
|
8
|
use File::Spec::Functions qw( catfile ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
46
|
|
21
|
1
|
|
|
1
|
|
632
|
use File::HomeDir (); |
|
1
|
|
|
|
|
5981
|
|
|
1
|
|
|
|
|
26
|
|
22
|
|
|
|
|
|
|
|
23
|
1
|
|
|
1
|
|
7
|
use vars qw( $VERSION $CONFIG $HOSTNAME ); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
3203
|
|
24
|
|
|
|
|
|
|
$VERSION = $Net::SSH::Perl::VERSION; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub version_string { |
27
|
1
|
|
|
1
|
0
|
2
|
my $class = shift; |
28
|
1
|
|
|
|
|
8
|
sprintf "Net::SSH::Perl Version %s, protocol version %s.%s.", |
29
|
|
|
|
|
|
|
$class->VERSION, PROTOCOL_MAJOR_1, PROTOCOL_MINOR_1; |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub _proto_init { |
33
|
1
|
|
|
1
|
|
2
|
my $ssh = shift; |
34
|
1
|
|
|
|
|
5
|
my $home = File::HomeDir->my_home; |
35
|
1
|
|
|
|
|
35
|
my $config = $ssh->{config}; |
36
|
|
|
|
|
|
|
|
37
|
1
|
50
|
|
|
|
4
|
unless ($config->get('user_known_hosts')) { |
38
|
1
|
50
|
|
|
|
4
|
defined $home or croak "Cannot determine home directory, please set the environment variable HOME"; |
39
|
1
|
|
|
|
|
7
|
$config->set('user_known_hosts', catfile($home, '.ssh', 'known_hosts')); |
40
|
|
|
|
|
|
|
} |
41
|
1
|
50
|
|
|
|
7
|
unless ($config->get('global_known_hosts')) { |
42
|
|
|
|
|
|
|
my $glob_known_hosts = $^O eq 'MSWin32' |
43
|
1
|
50
|
|
|
|
4
|
? catfile( $ENV{WINDIR}, 'ssh_known_hosts' ) |
44
|
|
|
|
|
|
|
: '/etc/ssh_known_hosts'; |
45
|
1
|
|
|
|
|
3
|
$config->set('global_known_hosts', $glob_known_hosts ); |
46
|
|
|
|
|
|
|
} |
47
|
1
|
50
|
|
|
|
2
|
unless (my $if = $config->get('identity_files')) { |
48
|
1
|
50
|
|
|
|
3
|
defined $home or croak "Cannot determine home directory, please set the environment variable HOME"; |
49
|
1
|
|
|
|
|
5
|
$config->set('identity_files', [ catfile($home, '.ssh', 'identity') ]); |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
1
|
|
|
|
|
3
|
for my $a (qw( password rhosts rhosts_rsa rsa ch_res )) { |
53
|
5
|
50
|
|
|
|
11
|
$config->set("auth_$a", 1) |
54
|
|
|
|
|
|
|
unless defined $config->get("auth_$a"); |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub _disconnect { |
59
|
1
|
|
|
1
|
|
2
|
my $ssh = shift; |
60
|
1
|
|
|
|
|
3
|
my $packet = $ssh->packet_start(SSH_MSG_DISCONNECT); |
61
|
1
|
50
|
|
|
|
21
|
$packet->put_str("@_") if @_; |
62
|
1
|
|
|
|
|
4
|
$packet->send; |
63
|
1
|
|
|
|
|
11
|
$ssh->{session} = {}; |
64
|
1
|
|
|
|
|
3
|
for my $key (qw( _cmd_stdout _cmd_stderr _cmd_exit )) { |
65
|
3
|
|
|
|
|
10
|
$ssh->{$key} = ""; |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
sub register_handler { |
70
|
0
|
|
|
0
|
1
|
0
|
my($ssh, $type, $sub, @extra) = @_; |
71
|
|
|
|
|
|
|
## XXX hack |
72
|
0
|
0
|
|
|
|
0
|
if ($type eq 'stdout') { |
|
|
0
|
|
|
|
|
|
73
|
0
|
|
|
|
|
0
|
$type = SSH_SMSG_STDOUT_DATA; |
74
|
|
|
|
|
|
|
} elsif ($type eq 'stderr') { |
75
|
0
|
|
|
|
|
0
|
$type = SSH_SMSG_STDERR_DATA; |
76
|
|
|
|
|
|
|
} |
77
|
0
|
|
|
|
|
0
|
$ssh->{client_handlers}{$type} = { code => $sub, extra => \@extra }; |
78
|
|
|
|
|
|
|
} |
79
|
0
|
|
|
0
|
0
|
0
|
sub handler_for { $_[0]->{client_handlers}{$_[1]} } |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub _login { |
82
|
0
|
|
|
0
|
|
0
|
my $ssh = shift; |
83
|
0
|
|
|
|
|
0
|
my $user = $ssh->{config}->get('user'); |
84
|
0
|
0
|
|
|
|
0
|
croak "No user defined" unless $user; |
85
|
|
|
|
|
|
|
|
86
|
0
|
|
|
|
|
0
|
$ssh->debug("Waiting for server public key."); |
87
|
0
|
|
|
|
|
0
|
my $packet = Net::SSH::Perl::Packet->read_expect($ssh, SSH_SMSG_PUBLIC_KEY); |
88
|
|
|
|
|
|
|
|
89
|
0
|
|
|
|
|
0
|
my $check_bytes = $packet->bytes(0, 8, ""); |
90
|
|
|
|
|
|
|
|
91
|
0
|
|
|
|
|
0
|
my %keys; |
92
|
0
|
|
|
|
|
0
|
for my $which (qw( public host )) { |
93
|
0
|
|
|
|
|
0
|
$keys{$which} = Net::SSH::Perl::Key::RSA1->new; |
94
|
0
|
|
|
|
|
0
|
$keys{$which}{rsa}{bits} = $packet->get_int32; |
95
|
0
|
|
|
|
|
0
|
$keys{$which}{rsa}{e} = $packet->get_mp_int; |
96
|
0
|
|
|
|
|
0
|
$keys{$which}{rsa}{n} = $packet->get_mp_int; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
0
|
|
|
|
|
0
|
my $protocol_flags = $packet->get_int32; |
100
|
0
|
|
|
|
|
0
|
my $supported_ciphers = $packet->get_int32; |
101
|
0
|
|
|
|
|
0
|
my $supported_auth = $packet->get_int32; |
102
|
|
|
|
|
|
|
|
103
|
0
|
|
|
|
|
0
|
$ssh->debug("Received server public key ($keys{public}{rsa}{bits} " . |
104
|
|
|
|
|
|
|
"bits) and host key ($keys{host}{rsa}{bits} bits)."); |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
my $session_id = |
107
|
0
|
|
|
|
|
0
|
_compute_session_id($check_bytes, $keys{host}, $keys{public}); |
108
|
0
|
|
|
|
|
0
|
$ssh->{session}{id} = $session_id; |
109
|
|
|
|
|
|
|
|
110
|
0
|
|
|
|
|
0
|
$ssh->check_host_key($keys{host}); |
111
|
|
|
|
|
|
|
|
112
|
0
|
|
|
|
|
0
|
my $session_key = join '', map chr rand(255), 1..32; |
113
|
0
|
|
|
|
|
0
|
my $skey = Math::GMP->new(0); |
114
|
0
|
|
|
|
|
0
|
for my $i (0..31) { |
115
|
0
|
|
|
|
|
0
|
$skey *= 2**8; |
116
|
0
|
0
|
|
|
|
0
|
$skey += $i < 16 ? |
117
|
|
|
|
|
|
|
vec($session_key, $i, 8) ^ vec($session_id, $i, 8) : |
118
|
|
|
|
|
|
|
vec($session_key, $i, 8); |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
0
|
0
|
|
|
|
0
|
if ($keys{public}{rsa}{n} < $keys{host}{rsa}{n}) { |
122
|
0
|
|
|
|
|
0
|
$skey = _rsa_public_encrypt($skey, $keys{public}); |
123
|
0
|
|
|
|
|
0
|
$skey = _rsa_public_encrypt($skey, $keys{host}); |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
else { |
126
|
0
|
|
|
|
|
0
|
$skey = _rsa_public_encrypt($skey, $keys{host}); |
127
|
0
|
|
|
|
|
0
|
$skey = _rsa_public_encrypt($skey, $keys{public}); |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
0
|
my($cipher, $cipher_name); |
131
|
0
|
0
|
|
|
|
0
|
if ($cipher_name = $ssh->{config}->get('cipher')) { |
132
|
0
|
|
|
|
|
0
|
$cipher = Net::SSH::Perl::Cipher::id($cipher_name); |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
else { |
135
|
0
|
|
|
|
|
0
|
my $cid; |
136
|
0
|
0
|
0
|
|
|
0
|
if (($cid = Net::SSH::Perl::Cipher::id('IDEA')) && |
|
|
0
|
0
|
|
|
|
|
137
|
|
|
|
|
|
|
Net::SSH::Perl::Cipher::supported($cid, $supported_ciphers)) { |
138
|
0
|
|
|
|
|
0
|
$cipher_name = 'IDEA'; |
139
|
0
|
|
|
|
|
0
|
$cipher = $cid; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
elsif (($cid = Net::SSH::Perl::Cipher::id('DES3')) && |
142
|
|
|
|
|
|
|
Net::SSH::Perl::Cipher::supported($cid, $supported_ciphers)) { |
143
|
0
|
|
|
|
|
0
|
$cipher_name = 'DES3'; |
144
|
0
|
|
|
|
|
0
|
$cipher = $cid; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
0
|
0
|
|
|
|
0
|
unless (Net::SSH::Perl::Cipher::supported($cipher, $supported_ciphers)) { |
149
|
0
|
|
|
|
|
0
|
croak "Selected cipher type $cipher_name not supported by server."; |
150
|
|
|
|
|
|
|
} |
151
|
0
|
|
|
|
|
0
|
$ssh->debug(sprintf "Encryption type: %s", $cipher_name); |
152
|
|
|
|
|
|
|
|
153
|
0
|
|
|
|
|
0
|
$packet = $ssh->packet_start(SSH_CMSG_SESSION_KEY); |
154
|
0
|
|
|
|
|
0
|
$packet->put_int8($cipher); |
155
|
0
|
|
|
|
|
0
|
$packet->put_chars($check_bytes); |
156
|
0
|
|
|
|
|
0
|
$packet->put_mp_int($skey); |
157
|
0
|
|
|
|
|
0
|
$packet->put_int32(0); ## No protocol flags. |
158
|
0
|
|
|
|
|
0
|
$packet->send; |
159
|
0
|
|
|
|
|
0
|
$ssh->debug("Sent encrypted session key."); |
160
|
|
|
|
|
|
|
|
161
|
0
|
|
|
|
|
0
|
$ssh->set_cipher($cipher_name, $session_key); |
162
|
0
|
|
|
|
|
0
|
$ssh->{session}{key} = $session_key; |
163
|
|
|
|
|
|
|
|
164
|
0
|
|
|
|
|
0
|
Net::SSH::Perl::Packet->read_expect($ssh, SSH_SMSG_SUCCESS); |
165
|
0
|
|
|
|
|
0
|
$ssh->debug("Received encryption confirmation."); |
166
|
|
|
|
|
|
|
|
167
|
0
|
|
|
|
|
0
|
$packet = $ssh->packet_start(SSH_CMSG_USER); |
168
|
0
|
|
|
|
|
0
|
$packet->put_str($user); |
169
|
0
|
|
|
|
|
0
|
$packet->send; |
170
|
|
|
|
|
|
|
|
171
|
0
|
|
|
|
|
0
|
$packet = Net::SSH::Perl::Packet->read($ssh); |
172
|
0
|
0
|
|
|
|
0
|
return 1 if $packet->type == SSH_SMSG_SUCCESS; |
173
|
|
|
|
|
|
|
|
174
|
0
|
0
|
|
|
|
0
|
if ($packet->type != SSH_SMSG_FAILURE) { |
175
|
0
|
|
|
|
|
0
|
$ssh->fatal_disconnect(sprintf |
176
|
|
|
|
|
|
|
"Protocol error: got %d in response to SSH_CMSG_USER", $packet->type); |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
0
|
|
|
|
|
0
|
my $auth_order = Net::SSH::Perl::Auth::auth_order(); |
180
|
0
|
|
|
|
|
0
|
for my $auth_id (@$auth_order) { |
181
|
0
|
0
|
|
|
|
0
|
next unless Net::SSH::Perl::Auth::supported($auth_id, $supported_auth); |
182
|
0
|
|
|
|
|
0
|
my $auth = Net::SSH::Perl::Auth->new(Net::SSH::Perl::Auth::name($auth_id), $ssh); |
183
|
0
|
|
|
|
|
0
|
my $valid = $auth->authenticate; |
184
|
0
|
0
|
|
|
|
0
|
return 1 if $valid; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
sub compression { |
189
|
10
|
|
|
10
|
1
|
16
|
my $ssh = shift; |
190
|
10
|
50
|
|
|
|
21
|
if (@_) { |
191
|
0
|
|
|
|
|
0
|
my $level = shift; |
192
|
0
|
|
|
|
|
0
|
$ssh->debug("Enabling compression at level $level."); |
193
|
0
|
|
|
|
|
0
|
$ssh->{session}{compression} = Net::SSH::Perl::Comp->new('Zlib', $level); |
194
|
|
|
|
|
|
|
} |
195
|
10
|
|
|
|
|
28
|
$ssh->{session}{compression}; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
sub _setup_connection { |
199
|
0
|
|
|
0
|
|
0
|
my $ssh = shift; |
200
|
|
|
|
|
|
|
|
201
|
0
|
0
|
|
|
|
0
|
$ssh->_connect unless $ssh->sock; |
202
|
0
|
0
|
|
|
|
0
|
$ssh->_login or |
203
|
|
|
|
|
|
|
$ssh->fatal_disconnect("Permission denied"); |
204
|
|
|
|
|
|
|
|
205
|
0
|
0
|
|
|
|
0
|
if ($ssh->{config}->get('compression')) { |
206
|
0
|
|
|
|
|
0
|
eval { require Compress::Zlib; }; |
|
0
|
|
|
|
|
0
|
|
207
|
0
|
0
|
|
|
|
0
|
if ($@) { |
208
|
0
|
|
|
|
|
0
|
$ssh->debug("Compression is disabled because Compress::Zlib can't be loaded."); |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
else { |
211
|
0
|
|
0
|
|
|
0
|
my $level = $ssh->{config}->get('compression_level') || 6; |
212
|
0
|
|
|
|
|
0
|
$ssh->debug("Requesting compression at level $level."); |
213
|
0
|
|
|
|
|
0
|
my $packet = $ssh->packet_start(SSH_CMSG_REQUEST_COMPRESSION); |
214
|
0
|
|
|
|
|
0
|
$packet->put_int32($level); |
215
|
0
|
|
|
|
|
0
|
$packet->send; |
216
|
|
|
|
|
|
|
|
217
|
0
|
|
|
|
|
0
|
$packet = Net::SSH::Perl::Packet->read($ssh); |
218
|
0
|
0
|
|
|
|
0
|
if ($packet->type == SSH_SMSG_SUCCESS) { |
219
|
0
|
|
|
|
|
0
|
$ssh->compression($level); |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
else { |
222
|
0
|
|
|
|
|
0
|
$ssh->debug("Warning: Remote host refused compression."); |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
0
|
0
|
|
|
|
0
|
if ($ssh->{config}->get('use_pty')) { |
228
|
0
|
|
|
|
|
0
|
$ssh->debug("Requesting pty."); |
229
|
0
|
|
|
|
|
0
|
my($packet); |
230
|
0
|
|
|
|
|
0
|
$packet = $ssh->packet_start(SSH_CMSG_REQUEST_PTY); |
231
|
0
|
|
|
|
|
0
|
my($term) = $ENV{TERM} =~ /(\S+)/; |
232
|
0
|
|
|
|
|
0
|
$packet->put_str($term); |
233
|
0
|
|
|
|
|
0
|
my $foundsize = 0; |
234
|
0
|
0
|
|
|
|
0
|
if (eval "require Term::ReadKey") { |
235
|
0
|
|
|
|
|
0
|
my @sz = Term::ReadKey::GetTerminalSize($ssh->sock); |
236
|
0
|
0
|
|
|
|
0
|
if (defined $sz[0]) { |
237
|
0
|
|
|
|
|
0
|
$foundsize = 1; |
238
|
0
|
|
|
|
|
0
|
$packet->put_int32($sz[0]); # width |
239
|
0
|
|
|
|
|
0
|
$packet->put_int32($sz[1]); # height |
240
|
0
|
|
|
|
|
0
|
$packet->put_int32($sz[2]); # xpix |
241
|
0
|
|
|
|
|
0
|
$packet->put_int32($sz[3]); # ypix |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
} |
244
|
0
|
0
|
|
|
|
0
|
if (!$foundsize) { |
245
|
0
|
|
|
|
|
0
|
$packet->put_int32(0) for 1..4; |
246
|
|
|
|
|
|
|
} |
247
|
0
|
|
|
|
|
0
|
$packet->put_int8(0); |
248
|
0
|
|
|
|
|
0
|
$packet->send; |
249
|
|
|
|
|
|
|
|
250
|
0
|
|
|
|
|
0
|
$packet = Net::SSH::Perl::Packet->read($ssh); |
251
|
0
|
0
|
|
|
|
0
|
unless ($packet->type == SSH_SMSG_SUCCESS) { |
252
|
0
|
|
|
|
|
0
|
$ssh->debug("Warning: couldn't allocate a pseudo tty."); |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
sub cmd { |
258
|
0
|
|
|
0
|
1
|
0
|
my $ssh = shift; |
259
|
0
|
|
|
|
|
0
|
my $cmd = shift; |
260
|
0
|
|
|
|
|
0
|
my $stdin = shift; |
261
|
|
|
|
|
|
|
|
262
|
0
|
|
|
|
|
0
|
$ssh->_setup_connection; |
263
|
|
|
|
|
|
|
|
264
|
0
|
|
|
|
|
0
|
my($packet); |
265
|
|
|
|
|
|
|
|
266
|
0
|
|
|
|
|
0
|
$ssh->debug("Sending command: $cmd"); |
267
|
0
|
|
|
|
|
0
|
$packet = $ssh->packet_start(SSH_CMSG_EXEC_CMD); |
268
|
0
|
|
|
|
|
0
|
$packet->put_str($cmd); |
269
|
0
|
|
|
|
|
0
|
$packet->send; |
270
|
|
|
|
|
|
|
|
271
|
0
|
0
|
|
|
|
0
|
if (defined $stdin) { |
272
|
0
|
|
|
|
|
0
|
my $chunk_size = 32000; |
273
|
0
|
|
|
|
|
0
|
while ($stdin) { |
274
|
0
|
|
|
|
|
0
|
my $chunk = substr($stdin, 0, $chunk_size, ''); |
275
|
0
|
|
|
|
|
0
|
$packet = $ssh->packet_start(SSH_CMSG_STDIN_DATA); |
276
|
0
|
|
|
|
|
0
|
$packet->put_str($chunk); |
277
|
0
|
|
|
|
|
0
|
$packet->send; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
0
|
|
|
|
|
0
|
$packet = $ssh->packet_start(SSH_CMSG_EOF); |
281
|
0
|
|
|
|
|
0
|
$packet->send; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
0
|
0
|
|
|
|
0
|
unless ($ssh->handler_for(SSH_SMSG_STDOUT_DATA)) { |
285
|
|
|
|
|
|
|
$ssh->register_handler(SSH_SMSG_STDOUT_DATA, |
286
|
0
|
|
|
0
|
|
0
|
sub { $ssh->{_cmd_stdout} .= $_[1]->get_str }); |
|
0
|
|
|
|
|
0
|
|
287
|
|
|
|
|
|
|
} |
288
|
0
|
0
|
|
|
|
0
|
unless ($ssh->handler_for(SSH_SMSG_STDERR_DATA)) { |
289
|
|
|
|
|
|
|
$ssh->register_handler(SSH_SMSG_STDERR_DATA, |
290
|
0
|
|
|
0
|
|
0
|
sub { $ssh->{_cmd_stderr} .= $_[1]->get_str }); |
|
0
|
|
|
|
|
0
|
|
291
|
|
|
|
|
|
|
} |
292
|
0
|
0
|
|
|
|
0
|
unless ($ssh->handler_for(SSH_SMSG_EXITSTATUS)) { |
293
|
|
|
|
|
|
|
$ssh->register_handler(SSH_SMSG_EXITSTATUS, |
294
|
0
|
|
|
0
|
|
0
|
sub { $ssh->{_cmd_exit} = $_[1]->get_int32 }); |
|
0
|
|
|
|
|
0
|
|
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
0
|
|
|
|
|
0
|
$ssh->debug("Entering interactive session."); |
298
|
0
|
0
|
|
|
|
0
|
$ssh->_start_interactive(defined $stdin ? 1 : 0); |
299
|
|
|
|
|
|
|
my($stdout, $stderr, $exit) = |
300
|
0
|
|
|
|
|
0
|
map $ssh->{"_cmd_$_"}, qw( stdout stderr exit ); |
301
|
|
|
|
|
|
|
|
302
|
0
|
|
|
|
|
0
|
$ssh->_disconnect; |
303
|
0
|
|
|
|
|
0
|
($stdout, $stderr, $exit); |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
sub shell { |
307
|
0
|
|
|
0
|
1
|
0
|
my $ssh = shift; |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
$ssh->{config}->set('use_pty', 1) |
310
|
0
|
0
|
|
|
|
0
|
unless defined $ssh->{config}->get('use_pty'); |
311
|
0
|
|
|
|
|
0
|
$ssh->_setup_connection; |
312
|
|
|
|
|
|
|
|
313
|
0
|
|
|
|
|
0
|
$ssh->debug("Requesting shell."); |
314
|
0
|
|
|
|
|
0
|
my $packet = $ssh->packet_start(SSH_CMSG_EXEC_SHELL); |
315
|
0
|
|
|
|
|
0
|
$packet->send; |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
$ssh->register_handler(SSH_SMSG_STDOUT_DATA, |
318
|
0
|
|
|
0
|
|
0
|
sub { syswrite STDOUT, $_[1]->get_str }); |
|
0
|
|
|
|
|
0
|
|
319
|
|
|
|
|
|
|
$ssh->register_handler(SSH_SMSG_STDERR_DATA, |
320
|
0
|
|
|
0
|
|
0
|
sub { syswrite STDERR, $_[1]->get_str }); |
|
0
|
|
|
|
|
0
|
|
321
|
0
|
|
|
0
|
|
0
|
$ssh->register_handler(SSH_SMSG_EXITSTATUS, sub {}); |
322
|
|
|
|
|
|
|
|
323
|
0
|
|
|
|
|
0
|
$ssh->debug("Entering interactive session."); |
324
|
0
|
|
|
|
|
0
|
$ssh->_start_interactive(0); |
325
|
|
|
|
|
|
|
|
326
|
0
|
|
|
|
|
0
|
$ssh->_disconnect; |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
sub open2 { |
330
|
0
|
|
|
0
|
0
|
0
|
my $ssh = shift; |
331
|
0
|
|
|
|
|
0
|
my($cmd) = @_; |
332
|
|
|
|
|
|
|
|
333
|
0
|
|
|
|
|
0
|
require Net::SSH::Perl::Handle::SSH1; |
334
|
|
|
|
|
|
|
|
335
|
0
|
0
|
|
|
|
0
|
unless ($cmd) { |
336
|
|
|
|
|
|
|
$ssh->{config}->set('use_pty', 1) |
337
|
0
|
0
|
|
|
|
0
|
unless defined $ssh->{config}->get('use_pty'); |
338
|
|
|
|
|
|
|
} |
339
|
0
|
|
|
|
|
0
|
$ssh->_setup_connection; |
340
|
|
|
|
|
|
|
|
341
|
0
|
0
|
|
|
|
0
|
if ($cmd) { |
342
|
0
|
|
|
|
|
0
|
$ssh->debug("Sending command: $cmd"); |
343
|
0
|
|
|
|
|
0
|
my $packet = $ssh->packet_start(SSH_CMSG_EXEC_CMD); |
344
|
0
|
|
|
|
|
0
|
$packet->put_str($cmd); |
345
|
0
|
|
|
|
|
0
|
$packet->send; |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
else { |
348
|
0
|
|
|
|
|
0
|
$ssh->debug("Requesting shell."); |
349
|
0
|
|
|
|
|
0
|
my $packet = $ssh->packet_start(SSH_CMSG_EXEC_SHELL); |
350
|
0
|
|
|
|
|
0
|
$packet->send; |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
|
353
|
0
|
|
|
|
|
0
|
my $read = Symbol::gensym; |
354
|
0
|
|
|
|
|
0
|
my $write = Symbol::gensym; |
355
|
0
|
|
|
|
|
0
|
tie *$read, 'Net::SSH::Perl::Handle::SSH1', 'r', $ssh; |
356
|
0
|
|
|
|
|
0
|
tie *$write, 'Net::SSH::Perl::Handle::SSH1', 'w', $ssh; |
357
|
|
|
|
|
|
|
|
358
|
0
|
|
|
|
|
0
|
$ssh->debug("Entering interactive session."); |
359
|
0
|
|
|
|
|
0
|
return ($read, $write); |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
0
|
|
|
0
|
0
|
0
|
sub break_client_loop { $_[0]->{_cl_quit_pending} = 1 } |
363
|
0
|
|
|
0
|
|
0
|
sub _quit_pending { $_[0]->{_cl_quit_pending} } |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
sub _start_interactive { |
366
|
0
|
|
|
0
|
|
0
|
my $ssh = shift; |
367
|
0
|
|
|
|
|
0
|
my($sent_stdin) = @_; |
368
|
|
|
|
|
|
|
|
369
|
0
|
|
|
|
|
0
|
my $s = IO::Select->new; |
370
|
0
|
|
|
|
|
0
|
$s->add($ssh->{session}{sock}); |
371
|
0
|
0
|
|
|
|
0
|
$s->add(\*STDIN) unless $sent_stdin; |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
CLOOP: |
374
|
0
|
|
|
|
|
0
|
$ssh->{_cl_quit_pending} = 0; |
375
|
0
|
|
|
|
|
0
|
while (!$ssh->_quit_pending) { |
376
|
0
|
|
|
|
|
0
|
my @ready = $s->can_read; |
377
|
0
|
|
|
|
|
0
|
for my $a (@ready) { |
378
|
0
|
0
|
|
|
|
0
|
if ($a == $ssh->{session}{sock}) { |
|
|
0
|
|
|
|
|
|
379
|
0
|
|
|
|
|
0
|
my $buf; |
380
|
0
|
|
|
|
|
0
|
my $len = sysread $a, $buf, 8192; |
381
|
0
|
0
|
|
|
|
0
|
$ssh->break_client_loop unless $len; |
382
|
0
|
|
|
|
|
0
|
($buf) = $buf =~ /(.*)/s; ## Untaint data. Anything allowed. |
383
|
0
|
|
|
|
|
0
|
$ssh->incoming_data->append($buf); |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
elsif ($a == \*STDIN) { |
386
|
0
|
|
|
|
|
0
|
my $buf; |
387
|
0
|
|
|
|
|
0
|
sysread STDIN, $buf, 8192; |
388
|
0
|
|
|
|
|
0
|
($buf) = $buf =~ /(.*)/s; ## Untaint data. Anything allowed. |
389
|
0
|
|
|
|
|
0
|
my $packet = $ssh->packet_start(SSH_CMSG_STDIN_DATA); |
390
|
0
|
|
|
|
|
0
|
$packet->put_str($buf); |
391
|
0
|
|
|
|
|
0
|
$packet->send; |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
|
395
|
0
|
|
|
|
|
0
|
while (my $packet = Net::SSH::Perl::Packet->read_poll($ssh)) { |
396
|
0
|
0
|
|
|
|
0
|
if (my $r = $ssh->handler_for($packet->type)) { |
397
|
0
|
|
|
|
|
0
|
$r->{code}->($ssh, $packet, @{ $r->{extra} }); |
|
0
|
|
|
|
|
0
|
|
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
else { |
400
|
0
|
|
|
|
|
0
|
$ssh->debug(sprintf |
401
|
|
|
|
|
|
|
"Warning: ignoring packet of type %d", $packet->type); |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
0
|
0
|
|
|
|
0
|
if ($packet->type == SSH_SMSG_EXITSTATUS) { |
405
|
0
|
|
|
|
|
0
|
my $packet = $ssh->packet_start(SSH_CMSG_EXIT_CONFIRMATION); |
406
|
0
|
|
|
|
|
0
|
$packet->send; |
407
|
0
|
|
|
|
|
0
|
$ssh->break_client_loop; |
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
|
411
|
0
|
0
|
|
|
|
0
|
last if $ssh->_quit_pending; |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
sub send_data { |
416
|
0
|
|
|
0
|
0
|
0
|
my $ssh = shift; |
417
|
0
|
|
|
|
|
0
|
my($data) = @_; |
418
|
0
|
|
|
|
|
0
|
my $packet = $ssh->packet_start(SSH_CMSG_STDIN_DATA); |
419
|
0
|
|
|
|
|
0
|
$packet->put_str($data); |
420
|
0
|
|
|
|
|
0
|
$packet->send; |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
sub set_cipher { |
424
|
0
|
|
|
0
|
1
|
0
|
my $ssh = shift; |
425
|
0
|
|
|
|
|
0
|
my $ciph = shift; |
426
|
0
|
|
|
|
|
0
|
$ssh->{session}{receive} = Net::SSH::Perl::Cipher->new($ciph, @_); |
427
|
0
|
|
|
|
|
0
|
$ssh->{session}{send} = Net::SSH::Perl::Cipher->new($ciph, @_); |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
|
430
|
5
|
|
|
5
|
1
|
10
|
sub send_cipher { $_[0]->{session}{send} } |
431
|
5
|
|
|
5
|
1
|
17
|
sub receive_cipher { $_[0]->{session}{receive} } |
432
|
0
|
|
|
0
|
1
|
|
sub session_key { $_[0]->{session}{key} } |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
1; |
435
|
|
|
|
|
|
|
__END__ |