fix(cgi-bin): avoid direct SSH calls

main
Tsu-ba-me 3 years ago
parent c7f63f4a4b
commit 23d818cfff
  1. 1
      Anvil/Tools.pm
  2. 79
      cgi-bin/manage_vnc_pipes
  3. 133
      tools/striker-start-ssh-tunnel

@ -1224,6 +1224,7 @@ sub _set_paths
'striker-parse-oui' => "/usr/sbin/striker-parse-oui", 'striker-parse-oui' => "/usr/sbin/striker-parse-oui",
'striker-prep-database' => "/usr/sbin/striker-prep-database", 'striker-prep-database' => "/usr/sbin/striker-prep-database",
'striker-scan-network' => "/usr/sbin/striker-scan-network", 'striker-scan-network' => "/usr/sbin/striker-scan-network",
'striker-start-ssh-tunnel' => "/usr/sbin/striker-start-ssh-tunnel",
stty => "/usr/bin/stty", stty => "/usr/bin/stty",
su => "/usr/bin/su", su => "/usr/bin/su",
'subscription-manager' => "/usr/sbin/subscription-manager", 'subscription-manager' => "/usr/sbin/subscription-manager",

@ -69,13 +69,19 @@ sub get_vnc_info
my $server_name = $parameters->{server_name}; my $server_name = $parameters->{server_name};
my $port_base = 5900; my $port_base = 5900;
# Requires root to access VM information. # Requires root to access VM information.
my $shell_call = "ssh -n root@".$host_name." \"virsh vncdisplay ".$server_name."\""; my $shell_call = "virsh vncdisplay ".$server_name;
my $vnc_info; my $vnc_info;
my ($shell_output, $shell_return_code) = $anvil->System->call({ shell_call => $shell_call }); my ($shell_output, $shell_error, $shell_return_code) = $anvil->Remote->call({
target => $host_name,
remote_user => "root",
shell_call => $shell_call,
'close' => 1
});
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => {
shell_call => $shell_call, shell_call => $shell_call,
shell_output => $shell_output, shell_output => $shell_output,
shell_error => $shell_error,
shell_return_code => $shell_return_code shell_return_code => $shell_return_code
} }); } });
@ -100,12 +106,18 @@ sub is_websockify_process
my $parameters = shift; my $parameters = shift;
my $host_name = $parameters->{host_name}; my $host_name = $parameters->{host_name};
my $ws_pid = $parameters->{ws_pid}; my $ws_pid = $parameters->{ws_pid};
my $shell_call = "ssh -n ".$host_name." \"ps -o comm -h -p ".$ws_pid."\""; my $shell_call = "ps -o comm -h -p ".$ws_pid;
my ($shell_output, $shell_return_code) = $anvil->System->call({ shell_call => $shell_call }); my ($shell_output, $shell_error, $shell_return_code) = $anvil->Remote->call({
target => $host_name,
remote_user => "admin",
shell_call => $shell_call,
'close' => 1
});
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => {
shell_call => $shell_call, shell_call => $shell_call,
shell_output => $shell_output, shell_output => $shell_output,
shell_error => $shell_error,
shell_return_code => $shell_return_code shell_return_code => $shell_return_code
} }); } });
@ -322,12 +334,18 @@ sub start_websockify
} }
} }
my $shell_call = "ssh -n ".$host_name." 'websockify ".$source_port." :".$target_port." &>/dev/null & echo pid:\$!'"; my $shell_call = "websockify ".$source_port." :".$target_port." &>/dev/null & echo pid:\$!";
my ($shell_output, $shell_return_code) = $anvil->System->call({ shell_call => $shell_call }); my ($shell_output, $shell_error, $shell_return_code) = $anvil->Remote->call({
target => $host_name,
remote_user => "admin",
shell_call => $shell_call,
'close' => 1
});
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => {
shell_call => $shell_call, shell_call => $shell_call,
shell_output => $shell_output, shell_output => $shell_output,
shell_error => $shell_error,
shell_return_code => $shell_return_code shell_return_code => $shell_return_code
} }); } });
@ -368,14 +386,22 @@ sub stop_websockify
if (is_websockify_process($parameters)) if (is_websockify_process($parameters))
{ {
my $shell_call = "ssh -n ".$host_name." \"kill ".$ws_pid."\""; my $shell_call = "kill ".$ws_pid;
my $remote_call_parameters = {
target => $host_name,
remote_user => "admin",
shell_call => $shell_call,
'close' => 1
};
my $shell_output; my $shell_output;
my $shell_error;
my $shell_return_code; my $shell_return_code;
($shell_output, $shell_return_code) = $anvil->System->call({ shell_call => $shell_call }); ($shell_output, $shell_error, $shell_return_code) = $anvil->Remote->call($remote_call_parameters);
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => {
shell_call => $shell_call, shell_call => $shell_call,
shell_output => $shell_output, shell_output => $shell_output,
shell_error => $shell_error,
shell_return_code => $shell_return_code shell_return_code => $shell_return_code
} }); } });
@ -384,8 +410,9 @@ sub stop_websockify
if (is_websockify_process($parameters)) if (is_websockify_process($parameters))
{ {
$shell_call = $shell_call =~ s/kill/kill -9/; $shell_call = $shell_call =~ s/kill/kill -9/;
$remote_call_parameters->{shell_call} = $shell_call;
($shell_output, $shell_return_code) = $anvil->System->call({ shell_call => $shell_call }); ($shell_output, $shell_error, $shell_return_code) = $anvil->Remote->call($remote_call_parameters);
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => {
shell_call => $shell_call, shell_call => $shell_call,
shell_output => $shell_output, shell_output => $shell_output,
@ -433,7 +460,11 @@ sub start_ssh_tunnel
} }
} }
my $shell_call = "ssh -nN -L ".$ssh_tunnel_forward_port.":localhost:".$ws_source_port." ".$ws_host_name." & echo pid:\$!"; my $shell_call = $anvil->data->{path}{exe}{'striker-start-ssh-tunnel'}
." --remote-user admin --target ".$ws_host_name
." --forward-local-port ".$ssh_tunnel_forward_port
." --forward-remote-port ".$ws_source_port
." & echo pid:\$!";
my ($shell_output, $shell_return_code) = $anvil->System->call({ shell_call => $shell_call }); my ($shell_output, $shell_return_code) = $anvil->System->call({ shell_call => $shell_call });
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => {
@ -480,18 +511,30 @@ sub stop_ssh_tunnel
if (is_ssh_process($parameters)) if (is_ssh_process($parameters))
{ {
my $shell_call = "kill ".$ssh_tunnel_pid; my $shell_call = "kill ".$ssh_tunnel_pid;
my $is_remote_call = (defined $host_name) and ($host_name ne $anvil->Get->host_name()) ? 1 : 0;
my $remote_call_parameters = {
target => $host_name,
remote_user => "admin",
shell_call => $shell_call,
'close' => 1
};
my $shell_output; my $shell_output;
my $shell_error;
my $shell_return_code; my $shell_return_code;
if ((defined $host_name) and ($host_name ne $anvil->Get->host_name())) if ($is_remote_call)
{ {
$shell_call = "ssh -n ".$host_name." \"".$shell_call."\""; ($shell_output, $shell_error, $shell_return_code) = $anvil->Remote->call($remote_call_parameters);
} }
else
{
($shell_output, $shell_return_code) = $anvil->System->call({ shell_call => $shell_call }); ($shell_output, $shell_return_code) = $anvil->System->call({ shell_call => $shell_call });
}
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => {
shell_call => $shell_call, shell_call => $shell_call,
shell_output => $shell_output, shell_output => $shell_output,
shell_error => $shell_error,
shell_return_code => $shell_return_code shell_return_code => $shell_return_code
} }); } });
@ -500,11 +543,21 @@ sub stop_ssh_tunnel
if (is_ssh_process($parameters)) if (is_ssh_process($parameters))
{ {
$shell_call = $shell_call =~ s/kill/kill -9/; $shell_call = $shell_call =~ s/kill/kill -9/;
$remote_call_parameters->{shell_call} = $shell_call;
if ($is_remote_call)
{
($shell_output, $shell_error, $shell_return_code) = $anvil->Remote->call($remote_call_parameters);
}
else
{
($shell_output, $shell_return_code) = $anvil->System->call({ shell_call => $shell_call }); ($shell_output, $shell_return_code) = $anvil->System->call({ shell_call => $shell_call });
}
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => {
shell_call => $shell_call, shell_call => $shell_call,
shell_output => $shell_output, shell_output => $shell_output,
shell_error => $shell_error,
shell_return_code => $shell_return_code shell_return_code => $shell_return_code
} }); } });
} }

@ -0,0 +1,133 @@
#!/usr/bin/perl
#
# Open an SSH tunnel using the Net::OpenSSH module and keep it opened with an infinite loop.
#
# Note: this is a temporary solution to avoid directly calling the SSH command.
#
use strict;
use warnings;
use Anvil::Tools;
use Net::OpenSSH;
$| = 1;
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD}))
{
$running_directory =~ s/^\./$ENV{PWD}/;
}
my $anvil = Anvil::Tools->new();
my $ssh_fh;
$anvil->Log->level({ set => 2 });
sub start_ssh_tunnel
{
my $parameters = shift;
# Required parameters:
my $remote_user = $parameters->{remote_user};
my $target = $parameters->{target};
my $forward_local_port = $parameters->{forward_local_port};
my $forward_remote_port = $parameters->{forward_remote_port};
if ((not defined $remote_user)
or (not defined $target)
or (not defined $forward_local_port)
or (not defined $forward_remote_port))
{
return 1;
}
# Optional parameters:
my $port = $parameters->{port} ? $parameters->{port} : 22;
my $ssh_fh_key = $remote_user."\@".$target.":".$port;
my $query = "
SELECT anv.anvil_password
FROM hosts AS hos
JOIN anvils AS anv
ON hos.host_uuid = anv.anvil_node1_host_uuid
OR hos.host_uuid = anv.anvil_node2_host_uuid
OR hos.host_uuid = anv.anvil_dr1_host_uuid
WHERE hos.host_name = ".$anvil->Database->quote($target)."
;";
my $password = $anvil->Database->query({ query => $query, source => $THIS_FILE, line => __LINE__ })->[0]->[0];
my ($output, $error, $return_code) = $anvil->Remote->call({
remote_user => $remote_user,
target => $target,
password => $password,
shell_call => $anvil->data->{path}{exe}{echo}." 1",
no_cache => 1,
});
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
error => $error,
return_code => $return_code
} });
if ($output eq "1")
{
$ssh_fh = $anvil->data->{cache}{ssh_fh}{$ssh_fh_key};
delete $anvil->data->{cache}{ssh_fh}{$ssh_fh_key};
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => {
is_ssh_fh_defined => defined $ssh_fh ? 1 : 0
} });
}
$ssh_fh->system({ ssh_opts => [ "-O", "forward",
"-L".$forward_local_port.":localhost:".$forward_remote_port ] });
return 0;
}
sub handle_stop_signals
{
if (defined $ssh_fh->disconnect)
{
$ssh_fh->disconnect();
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => {
message => "SSH tunnel disconnected."
} });
}
$anvil->nice_exit({ exit_code => 0 });
}
$SIG->{INT} = \&handle_stop_signals;
$SIG->{TERM} = \&handle_stop_signals;
$anvil->Get->switches;
$anvil->Database->connect;
$anvil->Log->entry({ source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132" });
if (not $anvil->data->{sys}{database}{connections})
{
# No databases, exit.
$anvil->Log->entry({ source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0003" });
$anvil->nice_exit({ exit_code => 1 });
}
if (start_ssh_tunnel({
remote_user => $anvil->data->{switches}{'remote-user'},
target => $anvil->data->{switches}{'target'},
port => $anvil->data->{switches}{'port'},
forward_local_port => $anvil->data->{switches}{'forward-local-port'},
forward_remote_port => $anvil->data->{switches}{'forward-remote-port'}
}) > 0)
{
$anvil->nice_exit({ exit_code => 1 });
}
while(1)
{
sleep(1);
}
Loading…
Cancel
Save