Set IPMI passwords to always be 16 char long and special chars removed.

* Created Convert->to_ipmi_password() which takes a password string,
  strips special characters, and shortens the results to 16 characters
  long. This should work with all v1.5, v2 and newer IPMI BMCs.
* Updated System->configure_ipmi() to remove the attempts to step-down
  the password to find one that fits the current IPMI host, now simply
  using the Convert->to_ipmi_password() password.

Signed-off-by: digimer <mkelly@alteeve.ca>
main
digimer 9 months ago
parent a28bb083fa
commit 8f090a1f43
  1. 42
      Anvil/Tools/Convert.pm
  2. 1
      Anvil/Tools/Get.pm
  3. 192
      Anvil/Tools/System.pm

@ -21,6 +21,7 @@ my $THIS_FILE = "Convert.pm";
# format_mmddyy_to_yymmdd # format_mmddyy_to_yymmdd
# host_name_to_ip # host_name_to_ip
# human_readable_to_bytes # human_readable_to_bytes
# to_ipmi_password
# round # round
# time # time
@ -1190,6 +1191,47 @@ sub human_readable_to_bytes
} }
=head2 to_ipmi_password
This takes a password (a string) and returns it in a format suitable for use by most any IPMI BMC. More specifically, spaces are removed, special characters are removed, and it is shortened to 16 characters.
parameters;
=head3 password (required)
This is the string to convert into an IPMI compatible password.
=cut
sub to_ipmi_password
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Convert->to_ipmi_password()" }});
# Setup my numbers.
my $password = $parameter->{password} ? $parameter->{password} : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
password => $anvil->Log->is_secure($password),,
}});
my $ipmi_password = $password;
$ipmi_password =~ s/ //g;
$ipmi_password =~ s/'//g;
$ipmi_password =~ s/!//g;
$ipmi_password =~ s/://g;
$ipmi_password =~ s/;//g;
$ipmi_password =~ s/<//g;
$ipmi_password =~ s/>//g;
$ipmi_password = substr($ipmi_password, 0, 16);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
ipmi_password => $anvil->Log->is_secure($ipmi_password),
}});
return($ipmi_password);
}
=head2 round =head2 round
This takes a number and rounds it to a given number of places after the decimal (defaulting to an even integer). This does financial-type rounding. This takes a number and rounds it to a given number of places after the decimal (defaulting to an even integer). This does financial-type rounding.

@ -12,6 +12,7 @@ use JSON;
use Net::Netmask; use Net::Netmask;
use Text::Diff; use Text::Diff;
use UUID::Tiny qw(:std); use UUID::Tiny qw(:std);
use String::ShellQuote;
our $VERSION = "3.0.0"; our $VERSION = "3.0.0";
my $THIS_FILE = "Get.pm"; my $THIS_FILE = "Get.pm";

@ -1989,7 +1989,6 @@ sub configure_ipmi
my $host_uuid = $anvil->Get->host_uuid; my $host_uuid = $anvil->Get->host_uuid;
my $ipmi_ip_address = ""; my $ipmi_ip_address = "";
my $ipmi_password = ""; my $ipmi_password = "";
my $password_length = 0;
my $subnet_mask = ""; my $subnet_mask = "";
my $gateway = ""; my $gateway = "";
my $in_network = ""; my $in_network = "";
@ -2039,13 +2038,11 @@ sub configure_ipmi
} }
# Get the password using the Striker password. # Get the password using the Striker password.
my $db_uuid = $anvil->data->{sys}{database}{read_uuid}; my $db_uuid = $anvil->data->{sys}{database}{read_uuid};
$ipmi_password = $anvil->data->{database}{$db_uuid}{password}; $ipmi_password = $anvil->Convert->to_ipmi_password({password => $anvil->data->{database}{$db_uuid}{password}});
$password_length = length(Encode::encode('UTF-8', $ipmi_password));
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
db_uuid => $db_uuid, db_uuid => $db_uuid,
ipmi_password => $anvil->Log->is_secure($ipmi_password), ipmi_password => $anvil->Log->is_secure($ipmi_password),
password_length => $password_length,
}}); }});
if ((not $anvil->Validate->ipv4({debug => $debug, ip => $ipmi_ip_address})) or (not $ipmi_password)) if ((not $anvil->Validate->ipv4({debug => $debug, ip => $ipmi_ip_address})) or (not $ipmi_password))
@ -2164,12 +2161,10 @@ LIMIT 1
# Make sure the IPMI IP, subnet mask and password are available. # Make sure the IPMI IP, subnet mask and password are available.
$ipmi_ip_address = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{ipmi_ip}; $ipmi_ip_address = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{ipmi_ip};
$ipmi_password = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password}; $ipmi_password = $anvil->Convert->to_ipmi_password({password => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password}});
$password_length = length(Encode::encode('UTF-8', $ipmi_password));
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
ipmi_ip_address => $ipmi_ip_address, ipmi_ip_address => $ipmi_ip_address,
ipmi_password => $anvil->Log->is_secure($ipmi_password), ipmi_password => $anvil->Log->is_secure($ipmi_password),
password_length => $password_length,
}}); }});
# Find the subnet the IPMI IP is in. # Find the subnet the IPMI IP is in.
@ -2225,18 +2220,6 @@ LIMIT 1
} }
} }
# If the password has spaces, some IPMI BMCs won't allow them. If we need to use it, we'll take out
# the spaces and shrink the length.
my $ipmi_no_space_password = "";
if ($ipmi_password =~ /\s/)
{
$ipmi_no_space_password = $ipmi_password;
$ipmi_no_space_password =~ s/\s//g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { ipmi_no_space_password => $ipmi_no_space_password }});
}
# Call dmidecode to see if there even is an IPMI BMC on this host. # Call dmidecode to see if there even is an IPMI BMC on this host.
my $host_ipmi = ""; my $host_ipmi = "";
my $has_ipmi = 0; my $has_ipmi = 0;
@ -2575,7 +2558,6 @@ LIMIT 1
# These need LAN Plus # These need LAN Plus
$lanplus = "yes-no" $lanplus = "yes-no"
} }
my $try_again = 1;
$host_ipmi = $anvil->System->test_ipmi({ $host_ipmi = $anvil->System->test_ipmi({
debug => $debug, debug => $debug,
ipmi_user => $user_name, ipmi_user => $user_name,
@ -2600,9 +2582,6 @@ LIMIT 1
host_uuid => $host_uuid, host_uuid => $host_uuid,
host_status => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_status}, host_status => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_status},
}); });
$try_again = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { try_again => $try_again }});
} }
else else
{ {
@ -2634,166 +2613,17 @@ LIMIT 1
host_uuid => $host_uuid, host_uuid => $host_uuid,
host_status => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_status}, host_status => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_status},
}); });
$try_again = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { try_again => $try_again }});
} }
else else
{ {
# If we used the no-space password, set it as the ipmi_password now. # Nothing more to do.
if ($ipmi_no_space_password) $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "error_0137", variables => {
{ user_name => $user_name,
$ipmi_password = $ipmi_no_space_password; user_number => $user_number,
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { ipmi_password => $ipmi_password }}); output => $output,
}
# Change the password and then try again.
my $escaped_ipmi_password = shell_quote($ipmi_password);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { escaped_ipmi_password => $escaped_ipmi_password }});
my ($output, $return_code) = $anvil->System->call({debug => $debug, secure => 1, shell_call => $anvil->data->{path}{exe}{ipmitool}." user set password ".$user_number." ".$escaped_ipmi_password});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code, return_code => $return_code,
}}); }});
if (($return_code) or ($output =~ /Password is too long/)) return('!!error!!');
{
# Try again with the 20-byte password.
my $twenty_byte_ipmi_password = $anvil->Words->shorten_string({
debug => $debug,
secure => 1,
string => $ipmi_password,
'length' => 20,
});
my $twenty_byte_escaped_ipmi_password = shell_quote($twenty_byte_ipmi_password);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => {
twenty_byte_ipmi_password => $twenty_byte_ipmi_password,
twenty_byte_escaped_ipmi_password => $twenty_byte_escaped_ipmi_password,
}});
my ($output, $return_code) = $anvil->System->call({debug => $debug, secure => 1, shell_call => $anvil->data->{path}{exe}{ipmitool}." user set password ".$user_number." ".$twenty_byte_escaped_ipmi_password});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
if ($return_code)
{
# Try once more with the 16-byte password.
my $sixteen_byte_ipmi_password = $anvil->Words->shorten_string({
debug => $debug,
secure => 1,
string => $ipmi_password,
'length' => 16,
});
my $sixteen_byte_escaped_ipmi_password = shell_quote($sixteen_byte_ipmi_password);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => {
sixteen_byte_ipmi_password => $sixteen_byte_ipmi_password,
sixteen_byte_escaped_ipmi_password => $sixteen_byte_escaped_ipmi_password,
}});
my ($output, $return_code) = $anvil->System->call({debug => $debug, secure => 1, shell_call => $anvil->data->{path}{exe}{ipmitool}." user set password ".$user_number." ".$sixteen_byte_escaped_ipmi_password});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
if ($return_code)
{
# Nothing more to do.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "error_0137", variables => {
user_name => $user_name,
user_number => $user_number,
output => $output,
return_code => $return_code,
}});
return('!!error!!');
}
else
{
# Looks like the 16-byte version worked.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0515"});
}
}
else
{
# Looks like the 20-byte version worked.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0514"});
}
}
else
{
# Looks like the password took.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0513"});
}
}
}
if ($try_again)
{
$host_ipmi = $anvil->System->test_ipmi({
debug => $debug,
ipmi_user => $user_name,
ipmi_password => $ipmi_password,
ipmi_target => $ipmi_ip_address,
lanplus => $lanplus,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { host_ipmi => $host_ipmi}});
if (($host_ipmi) && ($host_ipmi ne "!!error!!"))
{
# We're good, password was changed!
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0511"});
# Update the database, in case needed.
my $host_uuid = $anvil->Get->host_uuid();
$anvil->Database->insert_or_update_hosts({
debug => $debug,
host_ipmi => $host_ipmi,
host_key => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_key},
host_name => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name},
host_type => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type},
host_uuid => $host_uuid,
host_status => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_status},
});
}
else
{
# Try it again from the dashboard, we may just not be able to talk to our own BMC (
# can happen on shared interfaces)
my $host_ipmi = $anvil->System->test_ipmi({
debug => $debug,
ipmi_user => $user_name,
ipmi_password => $ipmi_password,
ipmi_target => $ipmi_ip_address,
lanplus => $lanplus,
target => $striker_host,
password => $striker_password,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { host_ipmi => $host_ipmi}});
if (($host_ipmi) && ($host_ipmi ne "!!error!!"))
{
# We're good!
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0511"});
# Update the database, in case needed.
my $host_uuid = $anvil->Get->host_uuid();
$anvil->Database->insert_or_update_hosts({
debug => $debug,
host_ipmi => $host_ipmi,
host_key => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_key},
host_name => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name},
host_type => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type},
host_uuid => $host_uuid,
host_status => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_status},
});
}
else
{
# Nothing worked. :(
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "error_0138", variables => {
user_name => $user_name,
user_number => $user_number,
}});
return('!!error!!');
}
} }
} }

Loading…
Cancel
Save