git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@12931 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
		
			
				
	
	
		
			167 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
 | |
| package xCAT_plugin::bmcconfig;
 | |
| use Data::Dumper;
 | |
| use xCAT::Table;
 | |
| use xCAT::MsgUtils;
 | |
| use xCAT::Utils;
 | |
| use IO::Select;
 | |
| use Socket;
 | |
| 
 | |
| sub handled_commands {
 | |
|     return {
 | |
|           getbmcconfig => 'bmcconfig',
 | |
|         };
 | |
| }
 | |
| 
 | |
| sub genpassword {
 | |
|   my $length = shift;
 | |
|   my $password='';
 | |
|   my $characters= 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890';
 | |
|   srand; #have to reseed, rand is not rand otherwise
 | |
|   while (length($password) < $length) {
 | |
|     $password .= substr($characters,int(rand 63),1);
 | |
|   }
 | |
|   return $password;
 | |
| }
 | |
| 
 | |
| sub net_parms {
 | |
|   my $ip = shift;
 | |
|   if (inet_aton($ip)) {
 | |
|      $ip = inet_ntoa(inet_aton($ip));
 | |
|   } else {
 | |
|      xCAT::MsgUtils->message("S","Unable to resolve $ip");
 | |
|      return undef;
 | |
|   }
 | |
|   my $nettab = xCAT::Table->new('networks');
 | |
|   unless ($nettab) { return undef };
 | |
|   my @nets = $nettab->getAllAttribs('net','mask','gateway');
 | |
|   foreach (@nets) {
 | |
|     my $net = $_->{'net'};
 | |
|     my $mask =$_->{'mask'};
 | |
|     my $gw = $_->{'gateway'};
 | |
|     $ip =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/;
 | |
|     my $ipnum = ($1<<24)+($2<<16)+($3<<8)+$4;
 | |
|     $mask =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/;
 | |
|     my $masknum = ($1<<24)+($2<<16)+($3<<8)+$4;
 | |
|     $net =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/ or next; #next if ipv6, TODO: IPv6 support
 | |
|     my $netnum = ($1<<24)+($2<<16)+($3<<8)+$4;
 | |
|     if ($gw eq '<xcatmaster>') {
 | |
| 	$gw=xCAT::Utils->my_ip_facing($ip);
 | |
|     }
 | |
|     if (($ipnum & $masknum)==$netnum) {
 | |
|       return ($ip,$mask,$gw);
 | |
|     } 
 | |
|   }
 | |
|   xCAT::MsgUtils->message("S","xCAT BMC configuration error, no appropriate network for $ip found in networks, unable to determine netmask");
 | |
| }
 | |
| 
 | |
|   
 | |
| sub ok_with_node {
 | |
|    my $node = shift;
 | |
|    #Here we connect to the node on a privileged port (in the clear) and ask the
 | |
|    #node if it just asked us for credential.  It's convoluted, but it is 
 | |
|    #a convenient way to see if root on the ip has approved requests for
 | |
|    #credential retrieval.  Given the nature of the situation, it is only ok
 | |
|    #to assent to such requests before users can log in.  During postscripts
 | |
|    #stage in stateful nodes and during the rc scripts of stateless boot
 | |
|    my $select = new IO::Select;
 | |
|    #sleep 0.5; # gawk script race condition might exist, try to lose just in case
 | |
|    my $sock = new IO::Socket::INET(PeerAddr=>$node,
 | |
|                                      Proto => "tcp",
 | |
|                                      PeerPort => shift);
 | |
|    my $rsp;
 | |
|    unless ($sock) {return 0};
 | |
|    $select->add($sock);
 | |
|    print $sock "CREDOKBYYOU?\n";
 | |
|    unless ($select->can_read(5)) { #wait for data for up to five seconds
 | |
|       return 0;
 | |
|    }
 | |
|    my $response = <$sock>;
 | |
|    chomp($response);
 | |
|    if ($response eq "CREDOKBYME") {
 | |
|       return 1;
 | |
|    }
 | |
|    return 0;
 | |
| }
 | |
| 
 | |
| sub process_request  {
 | |
|   my $request = shift;
 | |
|   my $callback = shift;
 | |
|   my $node = $request->{'_xcat_clienthost'}->[0];
 | |
|   unless (ok_with_node($node,300)) {
 | |
|      $callback->({error=>["Unable to prove root on your IP approves of this request"],errorcode=>[1]});
 | |
|      return;
 | |
|   }
 | |
|   #my $sitetable = xCAT::Table->new('site');
 | |
|   my $ipmitable = xCAT::Table->new('ipmi');
 | |
|   my $passtable = xCAT::Table->new('passwd');
 | |
|   my $tmphash;
 | |
|   my $username = 'USERID';
 | |
|   my $gennedpassword=0;
 | |
|   my $bmc;
 | |
|   my $password = 'PASSW0RD';
 | |
|   if ($passtable) { ($tmphash)=$passtable->getAttribs({key=>'ipmi'},'username','password'); }
 | |
|   #Check for generics, can grab for both user and pass with a query
 | |
|   #since they cannot be in disparate records in passwd tab
 | |
|   if ($tmphash->{username}) { 
 | |
|     $username=$tmphash->{username};
 | |
|   }
 | |
|   if ($tmphash->{password}) { #It came for free with the last query
 | |
|     $password=$tmphash->{password};
 | |
|   }
 | |
|   #$tmphash=($sitetable->getAttribs({key=>'genpasswords'},'value'))[0];
 | |
|   my @entries =  xCAT::Utils->get_site_attribute("genpasswords");
 | |
|   my $site_entry = $entries[0];
 | |
|   if ($site_entry eq "1" or $site_entry  =~ /y(es)?/i) {
 | |
|     $password = genpassword(10)."1cA!";
 | |
|     $gennedpassword=1;
 | |
|     $tmphash=$ipmitable->getNodeAttribs($node,['bmc','username','bmcport','taggedvlan']);
 | |
|   } else {
 | |
|     $tmphash=$ipmitable->getNodeAttribs($node,['bmc','username','bmcport','password','taggedvlan']);
 | |
|     if ($tmphash->{password}) {
 | |
|       $password = $tmphash->{password};
 | |
|     }
 | |
|   }
 | |
|   my $bmcport;
 | |
|   if (defined $tmphash->{bmcport}) {
 | |
|       $bmcport = $tmphash->{bmcport};
 | |
|   }
 | |
|   if ($tmphash->{bmc} ) {
 | |
|     $bmc=$tmphash->{bmc};
 | |
|   }
 | |
|   if ($tmphash->{username}) {
 | |
|     $username = $tmphash->{username};
 | |
|   }
 | |
|   unless (defined $bmc) {
 | |
|      xCAT::MsgUtils->message('S',"Unable to identify bmc for $node, refusing to give config data");
 | |
|      $callback->({error=>["Invalid table configuration for bmcconfig"],errorcode=>[1]});
 | |
|      return 1;
 | |
|   }
 | |
|   foreach my $sbmc (split /,/,$bmc) {
 | |
| 	  (my $ip,my $mask,my $gw) = net_parms($sbmc);
 | |
| 	  unless ($ip and $mask and $username and $password) {
 | |
| 	     xCAT::MsgUtils->message('S',"Unable to determine IP, netmask, username, and/or pasword for $sbmc, ensure that host resolution is working.  Best guess parameters would have been: IP: '$ip', netmask: '$netmask', username: '$username', password: '$password'",  );
 | |
| 	     $callback->({error=>["Invalid table configuration for bmcconfig"],errorcode=>[1]});
 | |
| 	     return 1;
 | |
| 	  }
 | |
| 	  my $response={bmcip=>$ip,netmask=>$mask,gateway=>$gw,username=>$username,password=>$password};
 | |
| 	  if (defined $bmcport) {
 | |
| 	      $response->{bmcport}=$bmcport;
 | |
| 	  }
 | |
| 	  if (defined $tmphash->{taggedvlan}) {
 | |
| 	      $response->{taggedvlan}=$tmphash->{taggedvlan};
 | |
| 	  }
 | |
|   	$callback->($response);
 | |
|   }
 | |
|   if ($gennedpassword) { # save generated password
 | |
|     $ipmitable->setNodeAttribs($node,{password=>$password});
 | |
|   }
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 1;
 | |
| 
 |