* Figured out how to collect a peer's data. Passwords are passed via the 'state' table. Created a setuid c-wrapper as well.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 5 years ago
parent 2906a42d96
commit 99e1e4faf2
  1. 2
      Anvil/Tools.pm
  2. 11
      Anvil/Tools/Database.pm
  3. 22
      Anvil/Tools/Storage.pm
  4. 95
      cgi-bin/striker
  5. 1
      rpm/SPECS/anvil.spec
  6. 7
      share/words.xml
  7. 98
      tools/striker-get-peer-data

@ -1013,6 +1013,7 @@ sub _set_paths
'anvil-update-states' => "/usr/sbin/anvil-update-states",
'anvil-update-system' => "/usr/sbin/anvil-update-system",
bridge => "/usr/sbin/bridge",
'call_striker-get-peer-data' => "/usr/sbin/call_striker-get-peer-data",
'chmod' => "/usr/bin/chmod",
'chown' => "/usr/bin/chown",
cibadmin => "/usr/sbin/cibadmin",
@ -1068,6 +1069,7 @@ sub _set_paths
'ssh-keyscan' => "/usr/bin/ssh-keyscan",
stonith_admin => "/usr/sbin/stonith_admin",
strings => "/usr/bin/strings",
'striker-get-peer-data' => "/usr/sbin/striker-get-peer-data",
'striker-manage-install-target' => "/usr/sbin/striker-manage-install-target",
'striker-manage-peers' => "/usr/sbin/striker-manage-peers",
'striker-prep-database' => "/usr/sbin/striker-prep-database",

@ -4371,6 +4371,8 @@ sub insert_or_update_states
my $state_host_uuid = defined $parameter->{state_host_uuid} ? $parameter->{state_host_uuid} : $anvil->data->{sys}{host_uuid};
my $state_note = defined $parameter->{state_note} ? $parameter->{state_note} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
uuid => $uuid,
"cache::database_handle::${uuid}" => $anvil->data->{cache}{database_handle}{$uuid},
uuid => $uuid,
file => $file,
line => $line,
@ -4380,6 +4382,15 @@ sub insert_or_update_states
state_note => $state_note,
}});
# If we were passed a database UUID, check for the open handle.
if ($uuid)
{
$anvil->data->{cache}{database_handle}{$uuid} = "" if not defined $anvil->data->{cache}{database_handle}{$uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"cache::database_handle::${uuid}" => $anvil->data->{cache}{database_handle}{$uuid},
}});
}
if (not $state_name)
{
# Throw an error and exit.

@ -2670,7 +2670,7 @@ sub write_file
my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root";
my $error = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 0, list => {
body => $secure ? $anvil->Words->string({key => "log_0186"}) : $body,
body => (not $secure) ? $body : $anvil->Log->is_secure($body),
file => $file,
group => $group,
mode => $mode,
@ -2687,11 +2687,10 @@ sub write_file
$user =~ s/^(\S+)\s.*$/$1/;
$group =~ s/^(\S+)\s.*$/$1/;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
group => $group,
user => $user,
group => $group,
user => $user,
}});
# Make sure the passed file is a full path and file name.
if ($file !~ /^\/\w/)
{
@ -2865,10 +2864,13 @@ fi";
# Nope.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0040", variables => { file => $file }});
$error = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { error => $error }});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { error => $error }});
if (not $error)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { directory => $directory }});
if (not -e $directory)
{
# Don't pass the mode as the file's mode is likely not executable.
@ -2882,6 +2884,7 @@ fi";
# If 'secure' is set, the file will probably contain sensitive data so touch the file and set
# the mode before writing it.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { secure => $secure }});
if ($secure)
{
$anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{touch}." ".$file});
@ -2890,15 +2893,21 @@ fi";
# Now write the file.
my $shell_call = $file;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, key => "log_0013", variables => { shell_call => $shell_call }});
open (my $file_handle, ">", $shell_call) or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => $secure, priority => "err", key => "log_0016", variables => { shell_call => $shell_call, error => $! }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 0, key => "log_0013", variables => { shell_call => $shell_call }});
#open (my $file_handle, ">", $shell_call) or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => $secure, priority => "err", key => "log_0016", variables => { shell_call => $shell_call, error => $! }});
open (my $file_handle, ">", $shell_call) or die "Failed to write: [$shell_call], error was: [".$!."]\n";;
print $file_handle $body;
close $file_handle;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { mode => $mode }});
if ($mode)
{
$anvil->Storage->change_mode({debug => $debug, path => $file, mode => $mode});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
user => $user,
group => $group,
}});
if (($user) or ($group))
{
$anvil->Storage->change_owner({debug => $debug, path => $file, user => $user, group => $group});
@ -2906,6 +2915,7 @@ fi";
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { error => $error }});
return($error);
}

@ -1057,69 +1057,66 @@ sub add_sync_peer
}
else
{
# Can we connect to the peer?
my ($output, $error, $return_code) = $anvil->Remote->call({
my $state_uuid = $anvil->Database->insert_or_update_states({
debug => 3,
shell_call => $anvil->data->{path}{exe}{dmidecode}." --string system-uuid",
password => $password,
target => $host,
port => $ssh_port,
file => $THIS_FILE,
line => __LINE__,
state_name => "peer::".$host."::password",
state_note => $password,
uuid => $anvil->data->{sys}{host_uuid}, # Only write to our DB, no reason to store elsewhere
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { state_uuid => $state_uuid }});
my ($output, $error, $return_code) = $anvil->System->call({
debug => 2,
shell_call => $anvil->data->{path}{exe}{'call_striker-get-peer-data'}." --target root\@".$host.":".$ssh_port." --state-uuid ".$state_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
error => $error,
return_code => $return_code,
}});
if ($error)
# Pull out the details
foreach my $line (split/\n/, $output)
{
# No access
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "striker_warning_0003"}) }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
if ($line =~ /host_name=(.*)$/)
{
$peer_host = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host => $peer_host }});
}
if ($line =~ /host_uuid=(.*)$/)
{
$peer_uuid = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_uuid => $peer_uuid }});
}
}
else
# Make sure the database entry is gone (striker-get-peer-data should have removed it, but lets be safe).
my $query = "DELETE FROM states WHERE state_name = ".$anvil->Database->quote("peer::".$host."::password").";";
$anvil->Database->write({uuid => $anvil->data->{sys}{host_uuid}, debug => 2, query => $query, source => $THIS_FILE, line => __LINE__});
if (not $anvil->Validate->is_uuid({uuid => $peer_uuid}))
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "striker_warning_0005", variables => { uuid => $peer_uuid }}) }});
}
# Lastly, if bi-directional is set, make sure we have a way to talk to it.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::new_peer_bidirection::value" => $anvil->data->{cgi}{new_peer_bidirection}{value} }});
if ($anvil->data->{cgi}{new_peer_bidirection}{value} eq "on")
{
# We got the peer's UUID. Get the hostname as well.
$peer_uuid = lc($output);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_uuid => $peer_uuid }});
# See which of our IPs match theirs. If the peer is a hostname, first
$use_ip = $anvil->System->find_matching_ip({host => $host});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_ip => $use_ip }});
if (not $anvil->Validate->is_uuid({uuid => $peer_uuid}))
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "striker_warning_0005", variables => { uuid => $peer_uuid }}) }});
}
else
if ((not $use_ip) or ($use_ip eq "!!error!!"))
{
my ($error, $output, $return_code) = $anvil->Remote->call({
debug => 2,
password => $password,
target => $host,
port => $ssh_port,
shell_call => $anvil->data->{path}{exe}{hostnamectl}." --static",
return_code => $return_code,
});
# Can't do bi-directional
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "striker_warning_0008", variables => { host => $host }}) }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
error => $error,
"form::error_massage" => $anvil->data->{form}{error_massage},
}});
$peer_host = $output;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host => $peer_host }});
# Lastly, if bi-directional is set, make sure we have a way to talk to it.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::new_peer_bidirection::value" => $anvil->data->{cgi}{new_peer_bidirection}{value} }});
if ($anvil->data->{cgi}{new_peer_bidirection}{value} eq "on")
{
# See which of our IPs match theirs. If the peer is a hostname, first
$use_ip = $anvil->System->find_matching_ip({host => $host});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_ip => $use_ip }});
if ((not $use_ip) or ($use_ip eq "!!error!!"))
{
# Can't do bi-directional
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "striker_warning_0008", variables => { host => $host }}) }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"form::error_massage" => $anvil->data->{form}{error_massage},
}});
}
}
}
}
}

@ -82,6 +82,7 @@ Requires: anvil-striker-extra
Requires: createrepo
Requires: dhcp-server
Requires: firefox
Requires: gcc
Requires: gdm
Requires: httpd
Requires: kernel-core

@ -757,6 +757,7 @@ Failed to promote the DRBD resource: [#!variable!resource!#] primary. Expected a
<key name="log_0432"><![CDATA[Database->archive_database() was not passed an array reference of tables to archive. Please pass an array reference using the 'tables' parameter.]]></key>
<key name="log_0433">The 'smaps' proc file for the process ID: [#!variable!pid!#] was not found. Did the program just close?</key>
<key name="log_0434">- The DRBD resource: [#!variable!resource!#] is in the role: [#!variable!role!#] already, no need to bring it up.</key>
<key name="log_0435">Program: [#!variable!program!#] running as the real user: [#!variable!real_user!# (#!variable!real_uid!#)] and effective user: [#!variable!effective_user!# (#!variable!effective_uid!#)].</key>
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">Test</key>
@ -869,7 +870,7 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st
<key name="striker_0071">Ping</key>
<key name="striker_0072">Bi-directional</key>
<key name="striker_0073">When checked, the Anvil! will ping the peer before trying to connect to the database. This speeds up skipping a database that is offline, but won't help if the databsae is behind a router. When unchecked, connections will be a touch faster when the database is available.</key>
<key name="striker_0074">When checked, the peer will be configure to add the local database as a peer at the same time that we add it to this system.</key>
<key name="striker_0074">When checked, the peer will be configured to add the local database as a peer at the same time that we add it to this system.</key>
<key name="striker_0075">Access</key>
<key name="striker_0076"><![CDATA[This tells Striker how to connect to the peer. The default username is '<span class="fixed_width">admin</span>', and the default port is '<span class="fixed_width">5432</span>'. If the peer uses these, then you only need to specify the IP address or hostname of the peer. If the user name is not '<span class="fixed_width">admin</span>', then you need to use the format '<span class="fixed_width">user@host</span>. If the TCP port is not '<span class="fixed_width">5432</span>', then you need to use '<span class="fixed_width">host:port</span>. If both user and port are different, use the format '<span class="fixed_width">user@host:port</span>'.]]></key>
<key name="striker_0077"><![CDATA[If '#!string!striker_0072!#' is set, we will need to update the peer's configuration. If the peer's SSH port is not '<span class="fixed_width">22</span>', you can append: '<span class="fixed_width">,ssh=X</span>' where 'X' is the SSH TCP port.]]></key>
@ -1046,8 +1047,8 @@ 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_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_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_0067"><![CDATA[Unable to connect to the database, unable to read the peer's password.]]></key>
<key name="error_0068"><![CDATA[There was a problem reading the password from the database.]]></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>

@ -5,10 +5,11 @@
#
# Exit codes;
# 0 = Normal exit.
# 1 = Password file given, but not found
# 2 = Password file given, but not readable
# 1 = No database connection.
# 2 = Password not found in the database.
# 3 = Peer not accessible
# 4 = Unable to find the peer's host UUID
# 5 =
#
use strict;
@ -31,12 +32,20 @@ $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->data->{switches}{target} = "";
$anvil->data->{switches}{'state-uuid'} = "";
$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->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'switches::target' => $anvil->data->{switches}{target},
'switches::state-uuid' => $anvil->data->{switches}{'state-uuid'},
}});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0435", variables => {
program => $THIS_FILE,
real_user => getpwuid($<),
real_uid => $<,
effective_user => getpwuid($>),
effective_uid => $>,
}});
$anvil->data->{target}{user} = "admin";
@ -176,57 +185,34 @@ sub get_host_uuid
sub get_password
{
my ($anvil) = @_;
# We'll pick up the peer's password from the database.
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
# No databases, exit.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0067"});
$anvil->nice_exit({exit_code => 1});
}
my $query = "SELECT state_note FROM states WHERE state_uuid=".$anvil->Database->quote($anvil->data->{switches}{'state-uuid'}).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }});
my $password = "";
if ($anvil->data->{switches}{password})
my $password = $anvil->Database->query({uuid => $anvil->data->{sys}{host_uuid}, debug => 2, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$password = "" if not defined $password;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { password => $password }});
if (not $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 }});
}
}
# Well poo.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0068"});
$anvil->nice_exit({exit_code => 2});
}
else
{
# We have the password. Delete the entry now.
my $query = "DELETE FROM states WHERE state_uuid=".$anvil->Database->quote($anvil->data->{switches}{'state-uuid'}).";";
$anvil->Database->write({uuid => $anvil->data->{sys}{host_uuid}, debug => 3, query => $query, source => $THIS_FILE, line => __LINE__});
}
return($password);

Loading…
Cancel
Save