Commit 5008ab6b authored by Leigh B Stoller's avatar Leigh B Stoller

Merge branch 'features/ipmi-separate-encryption-keys'

parents 2a1b2451 609ca2e0
......@@ -3527,6 +3527,10 @@ CREATE TABLE `outlets_remoteauth` (
`key_role` varchar(64) NOT NULL default '',
`key_uid` varchar(64) NOT NULL default '',
`mykey` text NOT NULL,
-- NOTE: These are mostly pulled from ipmitool. Other protocols may need
-- other values or not care at all, hence the addition of OTHER to the
-- list and a default of NULL.
`key_privlvl` enum('CALLBACK','USER','OPERATOR','ADMINISTRATOR','OTHER') DEFAULT NULL,
PRIMARY KEY (`node_id`,`key_type`,`key_role`,`key_uid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
......
#
# IPMIv2 Separate (Kg) Encryption Key and Privileges Levels
#
# Actually, it turns out that the current schema's PRIMARY KEY already supports
# storing a separate Kg key from the user(s) passwords, so we just need to
# update the libs to pull all of the rows for that part.
#
use strict;
use libdb;
sub DoUpdate($$$)
{
my ($dbhandle, $dbname, $version) = @_;
DBQueryFatal(<<'SQL'
ALTER TABLE outlets_remoteauth
ADD COLUMN key_privlvl
ENUM ('CALLBACK', 'USER', 'OPERATOR', 'ADMINISTRATOR', 'OTHER') DEFAULT NULL
SQL
);
return 0;
}
1;
# Local Variables:
# mode:perl
# End:
# vim: set ft=perl et sw=4 ts=4:
......@@ -40,9 +40,12 @@
package power_ilo;
use strict;
use warnings;
use Exporter;
@ISA = ("Exporter");
@EXPORT = qw( iloctrl );
our @ISA = ("Exporter");
our @EXPORT = qw( iloctrl );
use lib "@prefix@/lib";
use libdb;
......@@ -55,6 +58,7 @@ use POSIX ":sys_wait_h";
my $debug = 0;
# Always parallelize for now cause we are vulnerable to timeouts with
# unreachable nodes or weird iLO crap.
# NOTE: ipmi doesn't appear to be handled if $parallelize isn't set.
my $parallelize = 1;
# Turn off line buffering on output
......@@ -99,7 +103,9 @@ sub iloctrl($$@) {
}
my ($IP) = $res->fetchrow();
$res = DBQueryFatal("select key_role,key_uid,mykey" .
# FIXED: Handle multiple rows here like power_ipmi.pm does.
# This is so we can grab a kgkey separately from the user password.
$res = DBQueryFatal("select key_role,key_uid,mykey,key_privlvl" .
" from outlets_remoteauth" .
" where node_id='$n' and key_type='$type'");
if (!defined($res) || !$res || $res->num_rows() == 0) {
......@@ -107,20 +113,53 @@ sub iloctrl($$@) {
++$exitval;
next;
}
my ($krole,$kuid,$kkey) = $res->fetchrow();
my ($krole,$kuid,$kkey,$kgkey,$kprivlvl);
while (my $row = $res->fetchrow_hashref()) {
$krole = $row->{'key_role'};
if ($krole eq "ipmi-passwd") {
$kuid = $row->{'key_uid'};
$kkey = $row->{'mykey'};
if ($row->{'key_privlvl'}) {
$kprivlvl = $row->{'key_privlvl'};
}
}
elsif ($krole eq "ipmi-kgkey") {
($kgkey = $row->{'mykey'}) =~ s/^0x//;
# NOTE: key_privlvl is currently ignored in case this is the
# only authentication mechanism being used.
}
}
$ilo_nodeinfo{$n} = [ $n,$IP,$krole,$kuid,$kkey ];
if ($kgkey && $kkey) {
$krole = 'ipmi-kgkey-passwd';
}
elsif ($kkey) {
$krole = 'ipmi-passwd';
}
elsif ($kgkey) {
$krole = 'ipmi-kgkey';
# restore previous behavior
$kkey = $kgkey;
$kgkey = undef;
$kprivlvl = undef;
}
else {
# all of the keys were empty which is weird and the last key_role
# returned from the db wins
}
$ilo_nodeinfo{$n} = [ $n,$IP,$krole,$kuid,$kkey,$kgkey,$kprivlvl ];
}
my $timeout = 30;
if ($parallelize) {
my $coderef = sub {
my ($n,$IP,$krole,$kuid,$kkey) = @{ $_[0] };
my ($n,$IP,$krole,$kuid,$kkey,$kgkey,$kprivlvl) = @{ $_[0] };
my $tret;
eval {
if ($type =~ /^ipmi/) {
$tret = ipmiexec($n,$type,$cmd,$IP,$krole,$kuid,$kkey,$timeout);
$tret = ipmiexec($n,$type,$cmd,$IP,$krole,$kuid,$kkey,$kgkey,$kprivlvl,$timeout);
} else {
$tret = iloexec($n,$type,$cmd,$IP,$krole,$kuid,$kkey,$timeout);
}
......@@ -252,11 +291,11 @@ sub iloexec($$$$$$$;$) {
$SIG{'ALRM'} = sub {
$SIG{'PIPE'} = 'IGNORE';
$SIG{'CHLD'} = 'IGNORE';
kill(INT,$pid);
kill('INT',$pid);
select(undef,undef,undef,0.1);
kill(TERM,$pid);
kill('TERM',$pid);
select(undef,undef,undef,0.1);
kill(KILL,$pid);
kill('KILL',$pid);
die "iloexec($node_id) timed out in ssh!";
};
......@@ -301,7 +340,7 @@ sub iloexec($$$$$$$;$) {
# Talk to ssh over the pty: wait for expected output and send responses
#
my @lines = ();
foreach $es (@expect_seq) {
foreach my $es (@expect_seq) {
my ($rval,$sval) = @$es;
my $found = 0;
......@@ -361,17 +400,17 @@ sub iloexec($$$$$$$;$) {
}
sleep(1);
}
kill(KILL,$pid) if (!$dead);
kill('KILL',$pid) if (!$dead);
# if we get here, things probably went ok...
return 0;
}
#
# Arguments: $node_id,$type,$cmd,$IP,$key_role,$key_uid,$key[,$timeout]
# Arguments: $node_id,$type,$cmd,$IP,$key_role,$key_uid,$key[,$kgkey,$privlvl,$timeout]
#
sub ipmiexec($$$$$$$;$) {
my ($node_id,$type,$cmd,$IP,$key_role,$key_uid,$key,$timeout) = @_;
sub ipmiexec($$$$$$$;$$$) {
my ($node_id,$type,$cmd,$IP,$key_role,$key_uid,$key,$kgkey,$privlvl,$timeout) = @_;
if ($debug) {
print "ipmiexec called with (" . join(',',@_) . ")\n";
......@@ -407,12 +446,15 @@ sub ipmiexec($$$$$$$;$) {
if ($key_role eq 'ipmi-passwd') {
$usekey = 0;
} elsif ($key_role eq 'ipmi-kgkey-passwd') {
$usekey = 1;
} elsif ($key_role eq 'ipmi-kgkey') {
if ($type eq 'ipmi15') {
warn "Cannot use key_role 'kgkey' for IPMI 1.5!";
return -21;
}
$usekey = 1;
$kgkey = $key;
} else {
warn "Unsupported IPMI key_role $key_role!";
return -14;
......@@ -421,13 +463,14 @@ sub ipmiexec($$$$$$$;$) {
# XXX IPMI takes about 40 seconds to timeout and doesn't
# have an option to control?!
my $ipmicmd = "ipmitool -I $iface -H $IP -U $key_uid -E -K power $cmd";
my $privlvl_args = ($privlvl) ? " -L $privlvl" : '';
my $ipmicmd = "ipmitool -I $iface -H $IP -U $key_uid $privlvl_args -E -K power $cmd";
print "*** Executing '$ipmicmd', output:\n"
if ($debug > 1);
# Set the password and key environment variables
$ENV{'IPMI_PASSWORD'} = substr($key, 0, $pwdmax);
$ENV{'IPMI_KGKEY'} = $key
$ENV{'IPMI_KGKEY'} = $kgkey
if ($usekey);
my $output = `$ipmicmd 2>&1`;
......@@ -447,3 +490,7 @@ sub ipmiexec($$$$$$$;$) {
}
1;
# vim: set ft=perl et sw=4 ts=8:
# Not sure what the (no)et sw=? ts=? rules should be in this file - they're kind of mixed.
# Seems like a leading tab in some places and then 4 expanded spaces. Maybe et sw=4 ts=8.
......@@ -81,7 +81,7 @@ sub new($$$;$) {
$self->{KGKEY} = "";
# Fetch authentication credentials from the DB.
my $res = DBQueryFatal("select key_role,key_uid,mykey" .
my $res = DBQueryFatal("select key_role,key_uid,mykey,key_privlvl" .
" from outlets_remoteauth" .
" where node_id='$devicename'".
" and key_type='$KTYPE'");
......@@ -93,9 +93,12 @@ sub new($$$;$) {
if ($role eq "ipmi-passwd") {
$self->{USERNAME} = $row->{'key_uid'};
$self->{PASSWORD} = $row->{'mykey'};
if ($row->{'key_privlvl'}) {
$self->{PRIVLVL} = $row->{'key_privlvl'};
}
}
elsif ($role eq "ipmi-kgkey") {
$self->{KGKEY} = $row->{'mykey'} =~ s/^0x//;
($self->{KGKEY} = $row->{'mykey'}) =~ s/^0x//;
}
}
}
......@@ -106,6 +109,9 @@ sub new($$$;$) {
} elsif ($self->{DEVICETYPE} eq "ipmi-ms") {
$self->{IPMICMD} .= " -I lanplus";
}
if ($self->{PRIVLVL}) {
$self->{IPMICMD} .= " -L $self->{PRIVLVL}";
}
# Do a quick query, to see if it works
system("$self->{IPMICMD} power status >/dev/null 2>\&1");
......@@ -274,3 +280,7 @@ sub _get_msaddr($$) {
# End with true
1;
# vim: set ft=perl et sw=4 ts=8:
# Not sure what the (no)et sw=? ts=? rules should be in this file - they're kind of mixed.
# Seems like a leading tab in some places and then 4 expanded spaces. Maybe et sw=4 ts=8.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment