#!/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 "\n"; print $sock " getcredentials\n"; print $sock " $req\n"; print $sock " 300\n"; print $sock "\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*/) { 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; }