* Created tools/striker-get-peer-data that will query a target's host UUID and host name. It's meant to be called by apache, avoiding apache itself needing to call ssh against a target machine.

* Fixed a bug in Storage->read_file() where a remote read, where the remote user wasn't specified, would cause the call to hange.
* Cleaned up striker->add_sync_peer() to use more clear variable names.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 5 years ago
parent b8816382b8
commit 2906a42d96
  1. 2
      Anvil/Tools/Log.pm
  2. 2
      Anvil/Tools/Remote.pm
  3. 2
      Anvil/Tools/Storage.pm
  4. 27
      cgi-bin/striker
  5. 2
      html/skins/alteeve/striker.html
  6. 6
      share/words.xml
  7. 233
      tools/striker-get-peer-data

@ -463,7 +463,7 @@ sub is_secure
if (not $anvil->Log->secure) if (not $anvil->Log->secure)
{ {
$password = "#!string!log_0186!#"; $password = $anvil->Words->string({key => "log_0186"});
} }
return($password); return($password);

@ -570,12 +570,14 @@ sub call
{ {
# Call with a timeout # Call with a timeout
($output, $error) = $ssh_fh->capture2({timeout => $timeout}, $shell_call."; ".$anvil->data->{path}{exe}{echo}." return_code:\$?"); ($output, $error) = $ssh_fh->capture2({timeout => $timeout}, $shell_call."; ".$anvil->data->{path}{exe}{echo}." return_code:\$?");
$output = "" if not defined $output;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { 'ssh_fh->error' => $ssh_fh->error }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { 'ssh_fh->error' => $ssh_fh->error }});
} }
else else
{ {
# Call without a timeout. # Call without a timeout.
($output, $error) = $ssh_fh->capture2($shell_call); ($output, $error) = $ssh_fh->capture2($shell_call);
$output = "" if not defined $output;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { 'ssh_fh->error' => $ssh_fh->error }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { 'ssh_fh->error' => $ssh_fh->error }});
} }
# Was there a problem? # Was there a problem?

@ -1540,7 +1540,7 @@ sub read_file
my $force_read = defined $parameter->{force_read} ? $parameter->{force_read} : 1; my $force_read = defined $parameter->{force_read} ? $parameter->{force_read} : 1;
my $password = defined $parameter->{password} ? $parameter->{password} : ""; my $password = defined $parameter->{password} ? $parameter->{password} : "";
my $port = defined $parameter->{port} ? $parameter->{port} : 22; my $port = defined $parameter->{port} ? $parameter->{port} : 22;
my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : ""; my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root";
my $secure = defined $parameter->{secure} ? $parameter->{secure} : 0; my $secure = defined $parameter->{secure} ? $parameter->{secure} : 0;
my $target = defined $parameter->{target} ? $parameter->{target} : ""; my $target = defined $parameter->{target} ? $parameter->{target} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {

@ -27,6 +27,7 @@ if (($running_directory =~ /^\./) && ($ENV{PWD}))
my $anvil = Anvil::Tools->new(); my $anvil = Anvil::Tools->new();
$anvil->Log->level({set => 2}); $anvil->Log->level({set => 2});
$anvil->Log->secure({set => 1});
### NOTE: We'll print the headers only when we need to. If we print them here, it will block cookies being set. ### NOTE: We'll print the headers only when we need to. If we print them here, it will block cookies being set.
# Setup some variables. # Setup some variables.
@ -974,16 +975,16 @@ sub add_sync_peer
my ($anvil) = @_; my ($anvil) = @_;
# Break up the user, host and port. If anything goes wrong, we'll set an error and send it back. # Break up the user, host and port. If anything goes wrong, we'll set an error and send it back.
my $user = $anvil->data->{sys}{database}{user}; my $pgsql_user = $anvil->data->{sys}{database}{user};
my $host = $anvil->data->{cgi}{new_peer_access}{value}; my $host = $anvil->data->{cgi}{new_peer_access}{value};
my $password = $anvil->data->{cgi}{new_peer_password}{value}; my $password = $anvil->data->{cgi}{new_peer_password}{value};
my $name = $anvil->data->{sys}{database}{name}; my $db_name = $anvil->data->{sys}{database}{name};
my $ping = $anvil->data->{cgi}{new_peer_ping}{value} eq "on" ? 1 : 0; my $ping = $anvil->data->{cgi}{new_peer_ping}{value} eq "on" ? 1 : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
user => $user, pgsql_user => $pgsql_user,
host => $host, host => $host,
password => $anvil->Log->is_secure($password), password => $anvil->Log->is_secure($password),
name => $name, db_name => $db_name,
ping => $ping, ping => $ping,
}}); }});
@ -1003,22 +1004,22 @@ sub add_sync_peer
} }
if ($host =~ /^(.*?)\@(.*?):(\d+)$/) if ($host =~ /^(.*?)\@(.*?):(\d+)$/)
{ {
$user = $1; $pgsql_user = $1;
$host = $2; $host = $2;
$pgsql_port = $3; $pgsql_port = $3;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host => $host, host => $host,
pgsql_port => $pgsql_port, pgsql_port => $pgsql_port,
user => $user, pgsql_user => $pgsql_user,
}}); }});
} }
elsif ($host =~ /^(.*?)\@(.*?)$/) elsif ($host =~ /^(.*?)\@(.*?)$/)
{ {
$user = $1; $pgsql_user = $1;
$host = $2; $host = $2;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host => $host, host => $host,
user => $user, pgsql_user => $pgsql_user,
}}); }});
} }
elsif ($host =~ /^(.*?):(\d+)$/) elsif ($host =~ /^(.*?):(\d+)$/)
@ -1034,7 +1035,7 @@ sub add_sync_peer
ssh_port => $ssh_port, ssh_port => $ssh_port,
host => $host, host => $host,
pgsql_port => $pgsql_port, pgsql_port => $pgsql_port,
user => $user, pgsql_user => $pgsql_user,
}}); }});
# Is the host a domain or IP? # Is the host a domain or IP?
@ -1058,7 +1059,7 @@ sub add_sync_peer
{ {
# Can we connect to the peer? # Can we connect to the peer?
my ($output, $error, $return_code) = $anvil->Remote->call({ my ($output, $error, $return_code) = $anvil->Remote->call({
debug => 2, debug => 3,
shell_call => $anvil->data->{path}{exe}{dmidecode}." --string system-uuid", shell_call => $anvil->data->{path}{exe}{dmidecode}." --string system-uuid",
password => $password, password => $password,
target => $host, target => $host,
@ -1129,7 +1130,7 @@ sub add_sync_peer
{ {
my $pgpass_file = "/tmp/.pgpass"; my $pgpass_file = "/tmp/.pgpass";
$password =~ s/:/\:/g; $password =~ s/:/\:/g;
my $body = $host.":".$pgsql_port.":".$name.":".$user.":".$password; my $body = $host.":".$pgsql_port.":".$db_name.":".$pgsql_user.":".$password;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => {
body => $body, body => $body,
}}); }});
@ -1142,7 +1143,7 @@ sub add_sync_peer
}); });
# This will return '1' only, if it works. # This will return '1' only, if it works.
my ($db_access, $return_code) = $anvil->System->call({shell_call => "PGPASSFILE=\"".$pgpass_file."\" ".$anvil->data->{path}{exe}{psql}." --host ".$host." --port ".$pgsql_port." --dbname ".$name." --username ".$user." --no-password --tuples-only --no-align --command \"SELECT 1\""}); my ($db_access, $return_code) = $anvil->System->call({shell_call => "PGPASSFILE=\"".$pgpass_file."\" ".$anvil->data->{path}{exe}{psql}." --host ".$host." --port ".$pgsql_port." --dbname ".$db_name." --username ".$pgsql_user." --no-password --tuples-only --no-align --command \"SELECT 1\""});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { db_access => $db_access, return_code => $return_code }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { db_access => $db_access, return_code => $return_code }});
if ($db_access ne "1") if ($db_access ne "1")
{ {
@ -1228,7 +1229,7 @@ sub add_sync_peer
{ {
# Show the screen the confirm the addition. # Show the screen the confirm the addition.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "confirm-new-peer", variables => { $anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "confirm-new-peer", variables => {
access => $user."@".$host.":".$pgsql_port, access => $pgsql_user."@".$host.":".$pgsql_port,
ping => $anvil->data->{cgi}{new_peer_ping}{value} ? "#!string!unit_0001!#" : "#!string!unit_0002!#", ping => $anvil->data->{cgi}{new_peer_ping}{value} ? "#!string!unit_0001!#" : "#!string!unit_0002!#",
bidirectional => $anvil->data->{cgi}{new_peer_bidirection}{value} ? "#!string!unit_0001!#" : "#!string!unit_0002!#", bidirectional => $anvil->data->{cgi}{new_peer_bidirection}{value} ? "#!string!unit_0001!#" : "#!string!unit_0002!#",
}}); }});

@ -455,7 +455,7 @@
</tr> </tr>
<tr> <tr>
<td class="padded_cell"> <td class="padded_cell">
<input type="text" id="new_peer_access" name="new_peer_access" placeholder="#!string!striker_0069!#" value="#!variable!new_peer_access!#" readonly onfocus="this.removeAttribute('readonly');" /> <input type="text" id="new_peer_access" name="new_peer_access" placeholder="#!string!striker_0069!#" value="#!variable!new_peer_access!#" />
</td> </td>
<td class="padded_cell"> <td class="padded_cell">
<!-- <!--

@ -864,7 +864,7 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st
<key name="striker_0066">Access to this machine via: [#!variable!network!#].</key> <key name="striker_0066">Access to this machine via: [#!variable!network!#].</key>
<key name="striker_0067">Save</key> <key name="striker_0067">Save</key>
<key name="striker_0068">Delete</key> <key name="striker_0068">Delete</key>
<key name="striker_0069">[db_user@]hostname_or_ip[:pgsql_port][,ssh=ssh_port]</key> <key name="striker_0069">[db_user@]host[:pgsql_port][,ssh=ssh_port]</key>
<key name="striker_0070">Add</key> <key name="striker_0070">Add</key>
<key name="striker_0071">Ping</key> <key name="striker_0071">Ping</key>
<key name="striker_0072">Bi-directional</key> <key name="striker_0072">Bi-directional</key>
@ -1046,6 +1046,10 @@ Failed to generate an RSA public key for the user: [#!variable!user!#]. The outp
<key name="error_0064">A request to active the logical volume: [#!variable!path!#] was made, but that path doesn't exist or isn't a block device.</key> <key name="error_0064">A request to active the logical volume: [#!variable!path!#] was made, but that path doesn't exist or isn't a block device.</key>
<key name="error_0065"><![CDATA[No program name given (via --program <name>), unable to proceed.]]></key> <key name="error_0065"><![CDATA[No program name given (via --program <name>), unable to proceed.]]></key>
<key name="error_0066"><![CDATA[The program: [#!variable!program!#] was not found to be running on this system.]]></key> <key name="error_0066"><![CDATA[The program: [#!variable!program!#] was not found to be running on this system.]]></key>
<key name="error_0067"><![CDATA[The password file: [#!variable!file!#] was not found.]]></key>
<key name="error_0068"><![CDATA[There was a problem reading the password file: [#!variable!file!#].]]></key>
<key name="error_0069"><![CDATA[Unable to access the host: [#!variable!host!#].]]></key>
<key name="error_0070"><![CDATA[Unable to find the host UUID on the host: [#!variable!host!#].]]></key>
<!-- These are units, words and so on used when displaying information. --> <!-- These are units, words and so on used when displaying information. -->
<key name="unit_0001">Yes</key> <key name="unit_0001">Yes</key>

@ -0,0 +1,233 @@
#!/usr/bin/perl
#
# This program is setuid 'admin' and calls a (new) peer to read its hostname and system UUID. It takes the
# target's password in via a file.
#
# Exit codes;
# 0 = Normal exit.
# 1 = Password file given, but not found
# 2 = Password file given, but not readable
# 3 = Peer not accessible
# 4 = Unable to find the peer's host UUID
#
use strict;
use warnings;
use Anvil::Tools;
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD}))
{
$running_directory =~ s/^\./$ENV{PWD}/;
}
# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete.
$| = 1;
my $anvil = Anvil::Tools->new();
$anvil->Log->level({set => 2});
$anvil->Log->secure({set => 1});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
# Read switches (target ([user@]host[:port]) and the file with the target's password.
$anvil->data->{switches}{target} = "";
$anvil->data->{switches}{password} = "";
$anvil->Get->switches;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
'switches::target' => $anvil->data->{switches}{target},
'switches::password' => $anvil->data->{switches}{password},
}});
$anvil->data->{target}{user} = "admin";
$anvil->data->{target}{host} = $anvil->data->{switches}{target};
$anvil->data->{target}{port} = 22;
$anvil->data->{target}{password} = get_password($anvil);
if ($anvil->data->{target}{host} =~ /^(.*?)@/)
{
$anvil->data->{target}{user} = $1;
$anvil->data->{target}{host} =~ s/^(.*?)@//;
}
if ($anvil->data->{target}{host} =~ /:(\d+)$/)
{
$anvil->data->{target}{port} = $1;
$anvil->data->{target}{host} =~ s/:(\d+)$//;
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'target::user' => $anvil->data->{target}{user},
'target::target' => $anvil->data->{target}{host},
'target::port' => $anvil->data->{target}{port},
'target::password' => $anvil->Log->is_secure($anvil->data->{target}{password}),
}});
my $host_uuid = get_host_uuid($anvil);
my $host_name = get_host_name($anvil);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host_uuid => $host_uuid,
host_name => $host_name,
}});
print "host_name=".$host_name."\n";
print "host_uuid=".$host_uuid."\n";
$anvil->nice_exit({code => 0});
#############################################################################################################
# Functions #
#############################################################################################################
# This tries to read the target's UUID either via host.uuid or via dmidecode.
sub get_host_name
{
my ($anvil) = @_;
my ($host_name, $error, $return_code) = $anvil->Remote->call({
debug => 2,
shell_call => $anvil->data->{path}{exe}{hostnamectl}." --static",
user => $anvil->data->{target}{user},
target => $anvil->data->{target}{host},
port => $anvil->data->{target}{port},
password => $anvil->data->{target}{password},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host_name => $host_name,
error => $error,
return_code => $return_code,
}});
return($host_name);
}
# This tries to read the target's UUID either via host.uuid or via dmidecode.
sub get_host_uuid
{
my ($anvil) = @_;
# This is the first thing called, so start by verifying we can talk to the target at all.
my $access = $anvil->Remote->test_access({
user => $anvil->data->{target}{user},
target => $anvil->data->{target}{host},
port => $anvil->data->{target}{port},
password => $anvil->data->{target}{password},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }});
if (not $access)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0069", variables => {
host => $anvil->data->{target}{user}.'@'.$anvil->data->{target}{host}.':'.$anvil->data->{target}{port},
}});
$anvil->nice_exit({exit_code => 3});
}
# Try to read the host.uuid file on the target, if possible.
my $host_uuid = "";
my $file_body = $anvil->Storage->read_file({
debug => 3,
file => $anvil->data->{path}{data}{host_uuid},
user => $anvil->data->{target}{user},
target => $anvil->data->{target}{host},
port => $anvil->data->{target}{port},
password => $anvil->data->{target}{password},
});
$file_body =~ s/\n$//g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_body => $file_body }});
if (($file_body eq "!!error!!") or (not $anvil->Validate->is_uuid({uuid => $file_body})))
{
# No good, Try dmidecode.
my ($output, $error, $return_code) = $anvil->Remote->call({
debug => 2,
shell_call => $anvil->data->{path}{exe}{dmidecode}." --string system-uuid",
user => $anvil->data->{target}{user},
target => $anvil->data->{target}{host},
port => $anvil->data->{target}{port},
password => $anvil->data->{target}{password},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
error => $error,
return_code => $return_code,
}});
if ($anvil->Validate->is_uuid({uuid => $output}))
{
# Got it.
$host_uuid = $output;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }});
}
}
else
{
$host_uuid = $file_body;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }});
}
# Exit out if I failed to get the host's UUID.
if (not $host_uuid)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0070", variables => {
host => $anvil->data->{target}{user}.'@'.$anvil->data->{target}{host}.':'.$anvil->data->{target}{port},
}});
$anvil->nice_exit({exit_code => 4});
}
return($host_uuid);
}
# This reads in the password from the password file, if possible.
sub get_password
{
my ($anvil) = @_;
my $password = "";
if ($anvil->data->{switches}{password})
{
my $found = 0;
my $file = $anvil->data->{switches}{password};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { file => $file }});
if (-e $file)
{
$found = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { found => $found }});
}
elsif ($anvil->data->{switches}{password} !~ /^\//)
{
$file = "/tmp/".$anvil->data->{switches}{password};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { file => $file }});
if (-e $file)
{
$found = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { found => $found }});
}
}
if (not $found)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0067", variables => { file => $file }});
$anvil->nice_exit({exit_code => 1});
}
else
{
# Read the file in.
my $body = $anvil->Storage->read_file({
debug => 3,
file => $file,
secure => 1,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, secure => 1, list => { body => $body }});
if ($body eq "!!error!!")
{
# Something went wrong.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0068", variables => { file => $file }});
$anvil->nice_exit({exit_code => 2});
}
else
{
$password = $body;
$password =~ s/\n$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, secure => 1, list => { password => $password }});
}
}
}
return($password);
}
Loading…
Cancel
Save