xcat-core/xCAT/postscripts/aixremoteshell
2014-07-22 07:22:55 -04:00

401 lines
9.9 KiB
Perl
Executable File

#!/usr/bin/perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#(C)IBM Corp
#
#-----------------------------------------------------------------------------
=head1 aixremoteshell
This sets up the remote shell for root on the AIX node,such that root can
login with no password. The default is /bin/rsh and
/bin/rcp but can be overriden by setting the useSSHonAIX attribute in the
site table to yes, in which case we will use ssh/scp.
The aixremoteshell postscripts will be called from remoteshell postscript
when on an AIX node. It will input a -d ( for do) flag, to indicate to run
If the flag is not input, the routine will do nothing. This is to have only
remoteshell in the postscripts table whether supporting AIX or Linux,
and better support mixed clusters.
=cut
#-----------------------------------------------------------------------------
#
# If USESSHONAIX does not exist or is no or 0 then
# setup .rhosts on the node
# else (ssh)
# setup the ssh keys on the node
# end
# MAIN
use strict;
use IO::Socket;
my $useSocketSSL=eval { require IO::Socket::SSL; };
if ($useSocketSSL) {
require IO::Socket::SSL;
}
use Getopt::Long;
my $rc = 0;
# Override from site table
my $usesshonaix = $ENV{'USESSHONAIX'};
my $master = $ENV{'MASTER'};
my $node = $ENV{'NODE'};
my $nodetype = $ENV{'NTYPE'};
my $enablesshbetweennodes = $ENV{'ENABLESSHBETWEENNODES'};
my $msg;
my $home;
my $cmd;
my $runscript;
my $username = "root";
Getopt::Long::Configure("bundling");
Getopt::Long::Configure("pass_through");
GetOptions(
'd|do' => \$runscript
);
# the postscript only runs if called with -d flag from remoteshell
unless ($runscript) {
my $msg = "aixremoteshell called without -d flag, do nothing.";
`logger -t xcat -p local4.err $msg`;
exit 0;
}
my @root = split ':', (`/bin/grep ^$username /etc/passwd 2>&1`);
$home = $root[5];
# root home directory must be root system
$rc = &runcmd("chown root $home");
if ($rc != 0)
{
my $msg = "It fails to chown root $home";
`logger -t xcat -p local4.err $msg`;
exit 1;
}
$rc = &runcmd("chgrp system $home");
if ($rc != 0)
{
my $msg = "It fails to chgrp system $home";
`logger -t xcat -p local4.err $msg`;
exit 1;
}
$usesshonaix =~ tr/a-z/A-Z/; # convert to upper
if ((!defined($usesshonaix)) || ($usesshonaix eq "0") || ($usesshonaix eq "NO"))
{ # setting up rsh
# setup .rhosts if not already setup
$cmd = "/bin/grep \"^$master root\" /.rhosts";
`$cmd 2>&1`;
my $rc = $? >> 8;
if ($rc)
{ # if not found, then add entry in .rhosts
&runcmd("/bin/echo $master root >> /.rhosts");
chmod 0600, "/.rhosts";
}
}
else
{
# setting up ssh
if (&setupSSH != 0) {
my $msg = "Failed to setup ssh on $node.\n";
`logger -t xcat -p local4.err $msg`;
# print $msg;
exit 0;
}
}
exit 0;
#
# Subroutines
#
sub setupSSH
{
my $sshdconfig = "/etc/ssh/sshd_config";
my $sshconfig = "/etc/ssh/ssh_config";
if (-e $sshdconfig)
{ # ssh installed
my $tmp="$sshdconfig.ORIG";
if (!(-e "$sshdconfig.ORIG"))
{
&runcmd("cp $sshdconfig $sshdconfig.ORIG");
}
&runcmd("echo \"KeyRegenerationInterval 0\" >>$sshdconfig");
&runcmd("echo \"X11Forwarding yes\" >>$sshdconfig");
&runcmd("echo \"MaxStartups 1024\" >>$sshdconfig");
&runcmd("echo \"ListenAddress ::\" >>$sshdconfig");
&runcmd("echo \"ListenAddress 0.0.0.0\" >>$sshdconfig");
#&runcmd("echo \"PasswordAuthentication no\" >>$sshdconfig");
if (!(-e "$sshconfig.ORIG"))
{
&runcmd("cp $sshconfig $sshconfig.ORIG");
}
&runcmd("echo \"StrictHostKeyChecking no\" >>$sshconfig");
}
else
{ # ssh not installed
my $msg = "Failed to setup ssh on $node, ssh not installed. \n";
`logger -t xcat -p local4.err $msg`;
exit 0;
}
if (-e "/xcatpost/_ssh")
{ # ssh public key available
$rc = &runcmd("mkdir -p /.ssh");
if ($rc == 0)
{
$rc = &runcmd("cp -fp /xcatpost/_ssh/* /.ssh");
if ($rc == 0)
{
$rc = &runcmd("chmod 0700 /.ssh");
$rc = &runcmd("chmod 0600 /.ssh/*");
}
}
}
else
{ # ssh keys not available
my $msg = "Failed to setup ssh on $node, ssh keys not available. \n";
`logger -t xcat -p local4.err $msg`;
exit 0;
}
# get the name of my service node/NIM master from /etc/xcatinfo
# ! use value of MASTER env variable instead
$::servnode = $master;
my $response=&getresponse("ssh_dsa_hostkey");
if (defined ($response) ) {
my $fd;
my $filename = "/etc/ssh/ssh_host_dsa_key";
&runcmd("mkdir -p /etc/ssh");
open($fd, '>',$filename);
print $fd $response;
close($fd);
# set the permissions
my $cmd = "chmod 600 $filename > /dev/null 2>&1";
&runcmd($cmd);
}
else {
$msg = "aixremoteshell: Could not get ssh_host_dsa_key file.\n";
`logger -t xcat -p local4.err $msg`;
}
my $response=&getresponse("ssh_rsa_hostkey");
if (defined ($response) ) {
my $fd;
my $filename = "/etc/ssh/ssh_host_rsa_key";
&runcmd("mkdir -p /etc/ssh");
open($fd, '>',$filename);
print $fd $response;
close($fd);
# set the permissions
my $cmd = "chmod 600 $filename > /dev/null 2>&1";
&runcmd($cmd);
}
else {
$msg = "aixremoteshell: Could not get ssh_host_rsa_key file.\n";
`logger -t xcat -p local4.err $msg`;
}
# is there is a ecdsa host key on the node, then get the one from the MN/SN
my $filename = "/etc/ssh/ssh_host_ecdsa_key";
if (-e $filename) {
my $response=&getresponse("ssh_ecdsa_hostkey");
if (defined ($response) ) {
my $fd;
&runcmd("mkdir -p /etc/ssh");
open($fd, '>',$filename);
print $fd $response;
close($fd);
# set the permissions
my $cmd = "chmod 600 $filename > /dev/null 2>&1";
&runcmd($cmd);
}
else {
$msg = "aixremoteshell: Could not get ssh_host_ecdsa_key file.\n";
`logger -t xcat -p local4.err $msg`;
}
}
if ( $nodetype eq "service") {
&runcmd("mkdir -p /etc/xcat/hostkeys; cp /etc/ssh/ssh* /etc/xcat/hostkeys/. > /dev/null 2>&1");
}
# Decide whether to enable passwordless ssh between the nodes
if ($enablesshbetweennodes eq "YES") {
my $response=&getresponse("ssh_root_key");
if (defined ($response) ) {
my $fd;
my $filename = "/.ssh/id_rsa";
&runcmd("mkdir -p /.ssh");
open($fd, '>',$filename);
print $fd $response;
close($fd);
# set the permissions
my $cmd = "chmod 600 $filename > /dev/null 2>&1";
&runcmd($cmd);
if ( -f "/.ssh/id_rsa" ) {
&runcmd("ssh-keygen -y -f /.ssh/id_rsa > /.ssh/id_rsa.pub");
}
}
else {
$msg = "aixremoteshell: Could not get id_rsa file.\n";
`logger -t xcat -p local4.err $msg`;
}
}
return 0;
}
#####################################################
#
# getresponse
# Request info from xcatd on the management node
#
# - uses SSL socket on port 3001 to connect to MN xcatd
# to make the request for info
#
#####################################################
sub getresponse
{
my ($req) = @_;
my $port = "3001";
# open listener connection to wait for check from management node
my $lpid = &openlistener();
# open a socket to request credentials
my $sock = IO::Socket::SSL->new(
PeerAddr => $::servnode,
PeerPort => $port,
Proto => 'tcp',
);
unless ($sock) {
my $msg = "aixremoteshell: Cannot connect to host \'$::servnode\'\n";
`logger -t xcat -p local4.err $msg`;
#print $msg;
kill 2, $lpid;
return undef;
}
# request must be in XML format
print $sock "<xcatrequest>\n";
print $sock " <command>getcredentials</command>\n";
print $sock " <arg>$req</arg>\n";
print $sock " <callback_port>300</callback_port>\n";
print $sock "</xcatrequest>\n";
#TODO - do we have to try again after waiting for a bit????
my $response='';
my $line;
while (defined ($line = <$sock>)) {
# skip xml tags
next if ($line =~ /^\s*</);
# once we get to serverdone we have the whole response
if ($line =~ m/<\/serverdone>/) {
last:
}
$response .= $line;
}
close ($sock);
kill 2, $lpid;
if ($response) {
return $response;
}
return undef;
}
#####################################################
#
# openlistener
# - fork a child process to respond to a check from the MN
#
#####################################################
sub openlistener
{
my $node = $ENV{'NODE'};
# fork a child process to open a socket to listen for communication
# from the server
my $pid = fork;
unless (defined $pid) {
# fork failed
$msg = "aixremoteshell: Could not fork process.\n";
`logger -t xcat -p local4.err $msg`;
print $msg;
return undef;
}
if ($pid != 0) {
# This is the parent process, just return
return $pid;
}
my $listener = IO::Socket::INET->new(
LocalPort => '300',
Proto => 'tcp',
Listen => '64',
Reuse => 1
);
unless ($listener) {
my $msg = "aixremoteshell: Cannot open socket on \'$node\'\n";
`logger -t xcat -p local4.err $msg`;
print $msg;
exit 1;
}
# xcatd sends a quick req to see if we are really asking
# for info - this listener checks for the req and says ok
my $client;
while ($client = $listener->accept()) {
# $client is the new connection
my $text=<$client>;
# see if we got "CREDOKBYYOU?"
if ($text =~ /CREDOKBYYOU?/) {
print $client "CREDOKBYME";
close($client);
close($listener);
exit 0;
}
close($client);
}
close($client);
close($listener);
exit 0;
}
#
# run the command
#
sub runcmd
{
my ($cmd) = @_;
my $rc = 0;
$cmd .= ' 2>&1';
$::outref = `$cmd`;
if ($?)
{
$rc = $? >> 8;
if ($rc > 0)
{
my $msg = "$cmd returned rc=$rc @$::outref\n";
`logger -t xcat -p local4.info $msg`;
# print $msg;
}
}
return 0;
}