You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
365 lines
13 KiB
365 lines
13 KiB
#!/usr/bin/perl |
|
# |
|
# This program is setuid 'admin' and calls a (new) peer to read its host name and system UUID. It takes the |
|
# target's password in via a file. |
|
# |
|
# Exit codes; |
|
# 0 = Normal exit. |
|
# 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; |
|
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. If the password is |
|
# passed directly, it will be used. Otherwise, the password will be read from the database. |
|
$anvil->data->{switches}{target} = ""; |
|
$anvil->data->{switches}{'state-uuid'} = ""; |
|
$anvil->data->{switches}{password} = ""; |
|
$anvil->Get->switches; |
|
$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'}, |
|
'switches::password' => $anvil->Log->is_secure($anvil->data->{switches}{password}), |
|
}}); |
|
|
|
$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"; |
|
$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); |
|
my ($host_os, $os_registered) = get_host_os($anvil); |
|
my $internet = $anvil->Network->check_internet({ |
|
remote_user => $anvil->data->{target}{user}, |
|
target => $anvil->data->{target}{host}, |
|
port => $anvil->data->{target}{port}, |
|
password => $anvil->data->{target}{password}, |
|
tries => 1, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
host_uuid => $host_uuid, |
|
host_name => $host_name, |
|
host_os => $host_os, |
|
os_registered => $os_registered, |
|
}}); |
|
print "connected=1\n"; |
|
print "host_name=".$host_name."\n"; |
|
print "host_uuid=".$host_uuid."\n"; |
|
print "host_os=".$host_os."\n"; |
|
print "os_registered=".$os_registered."\n"; |
|
print "internet=".$internet."\n"; |
|
|
|
$anvil->nice_exit({exit_code => 0}); |
|
|
|
|
|
############################################################################################################# |
|
# Functions # |
|
############################################################################################################# |
|
|
|
# This tries to read the target's OS |
|
sub get_host_os |
|
{ |
|
my ($anvil) = @_; |
|
|
|
my $host_os = "unknown"; |
|
my $os_registered = "n/a"; |
|
|
|
# We can't assume that rsync exists, so we'll cat the file. |
|
my $shell_call = " |
|
if [ -e '".$anvil->data->{path}{data}{'redhat-release'}."' ]; |
|
then |
|
".$anvil->data->{path}{exe}{cat}." ".$anvil->data->{path}{data}{'redhat-release'}." |
|
fi; |
|
"; |
|
my ($file_body, $error, $return_code) = $anvil->Remote->call({ |
|
debug => 3, |
|
shell_call => $shell_call, |
|
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 => { |
|
file_body => $file_body, |
|
error => $error, |
|
return_code => $return_code, |
|
}}); |
|
$file_body =~ s/\n$//g; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_body => $file_body }}); |
|
if ($file_body) |
|
{ |
|
if ($file_body =~ /Red Hat .*? release (\d+\.\d+) /) |
|
{ |
|
$host_os = "rhel ".$1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_os => $host_os }}); |
|
} |
|
} |
|
|
|
# If the OS is 'rhel', see if it is registered. |
|
if ($host_os =~ /^rhel /) |
|
{ |
|
# Is it subscribed? This isn't the best call to make, but it seems to be the one that returns |
|
# the fastest. Return code of '0' is registered, return code of '1' is not or not verified. |
|
my ($output, $error, $return_code) = $anvil->Remote->call({ |
|
debug => 2, |
|
shell_call => $anvil->data->{path}{exe}{'subscription-manager'}." identity", |
|
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, |
|
}}); |
|
|
|
# Possible output; |
|
=cut |
|
system identity: 3a9065a1-625a-48e1-86f4-97a3eac4b730 |
|
name: el8-striker01.digimer.ca |
|
org name: xxx |
|
org ID: yyy |
|
# rc:0 |
|
|
|
This system is not yet registered. Try 'subscription-manager register --help' for more information. |
|
# rc:1 |
|
|
|
Network error, unable to connect to server. Please see /var/log/rhsm/rhsm.log for more information. |
|
# rc:70 |
|
=cut |
|
if ($return_code eq "0") |
|
{ |
|
$os_registered = "yes"; |
|
} |
|
elsif ($return_code eq "1") |
|
{ |
|
$os_registered = "no"; |
|
} |
|
elsif ($return_code eq "70") |
|
{ |
|
# Unable to check, maybe, maybe not? |
|
$os_registered = "offline"; |
|
} |
|
} |
|
|
|
return($host_os, $os_registered); |
|
} |
|
|
|
# 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 => 3, |
|
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({ |
|
debug => 3, |
|
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) |
|
{ |
|
print "connected=0\n"; |
|
$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. |
|
# We can't assume that rsync exists, so we'll cat the file. |
|
my $shell_call = " |
|
if [ -e '".$anvil->data->{path}{data}{host_uuid}."' ]; |
|
then |
|
".$anvil->data->{path}{exe}{cat}." ".$anvil->data->{path}{data}{host_uuid}." |
|
fi; |
|
"; |
|
my ($file_body, $error, $return_code) = $anvil->Remote->call({ |
|
debug => 3, |
|
shell_call => $shell_call, |
|
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 => { |
|
file_body => $file_body, |
|
error => $error, |
|
return_code => $return_code, |
|
}}); |
|
$file_body =~ s/\n$//g; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_body => $file_body }}); |
|
|
|
my $host_uuid = ""; |
|
if ((not $file_body) or (not $anvil->Validate->uuid({uuid => $file_body}))) |
|
{ |
|
# No good, Try dmidecode. |
|
my ($output, $error, $return_code) = $anvil->Remote->call({ |
|
debug => 3, |
|
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->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) |
|
{ |
|
print "connected=0\n"; |
|
$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) = @_; |
|
|
|
# If we were given the password directly, use it. |
|
if ($anvil->data->{switches}{password}) |
|
{ |
|
return($anvil->data->{switches}{password}); |
|
} |
|
|
|
# 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. |
|
print "connected=0\n"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0067"}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# Do we have a (valid) state_uuid? |
|
if (not $anvil->data->{switches}{'state-uuid'}) |
|
{ |
|
print "connected=0\n"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0083"}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
elsif (not $anvil->Validate->uuid({uuid => $anvil->data->{switches}{'state-uuid'}})) |
|
{ |
|
print "connected=0\n"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0082", variables => {state_uuid => $anvil->data->{switches}{'state-uuid'} }}); |
|
$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 = $anvil->Database->query({uuid => $anvil->data->{sys}{host_uuid}, debug => 3, 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) |
|
{ |
|
# Well poo. |
|
print "connected=0\n"; |
|
$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); |
|
}
|
|
|