git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@6167 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
		
			
				
	
	
		
			367 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			367 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| # IBM(c) 2010 EPL license http://www.eclipse.org/legal/epl-v10.html
 | |
| package xCAT_plugin::activedirectory;
 | |
| BEGIN
 | |
| {
 | |
|       $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
 | |
| }
 | |
| my $callback;
 | |
| use lib "$::XCATROOT/lib/perl";
 | |
| use Getopt::Long;
 | |
| use xCAT::ADUtils;
 | |
| use Net::DNS;
 | |
| use strict;
 | |
| 
 | |
| sub handled_commands { 
 | |
|     return {
 | |
|         clusteruseradd => 'site:directoryprovider',
 | |
|         clusteruserdel => 'site:directoryprovider',
 | |
|         clusteruserlist => 'site:directoryprovider',
 | |
|         hostaccountlist => 'site:directoryprovider',
 | |
|         hostaccountadd => 'site:directoryprovider',
 | |
|         hostaccountdel => 'site:directoryprovider',
 | |
|     };
 | |
| }
 | |
| 
 | |
| sub process_request {
 | |
|     $ENV{LDAPRC}='ad.ldaprc'; #after examining openldap source, this is the best way to get their libraries to source /etc/xcat/ad.ldaprc
 | |
|     $ENV{HOME}='/etc/xcat';
 | |
|     my $request = shift;
 | |
|     my $command = $request->{command}->[0];
 | |
|     $callback = shift;
 | |
|     my $doreq = shift;
 | |
|     use Data::Dumper;
 | |
|     my $sitetab = xCAT::Table->new('site');
 | |
|     my $domain;
 | |
|     $domain = $sitetab->getAttribs({key=>'domain'},['value']);
 | |
|     if ($domain and $domain->{value}) { 
 | |
|         $domain = $domain->{value};
 | |
|     } else {
 | |
|         $domain = undef;
 | |
|     }
 | |
|     #TODO: if multi-domain support implemented, use the domains table to reference between realm and domain  
 | |
|     my $server = $sitetab->getAttribs({key=>'directoryserver'},['value']);
 | |
|     my $realm = $sitetab->getAttribs({key=>'realm'},['value']);
 | |
|     if ($realm and $realm->{value}) {
 | |
|         $realm = $realm->{value};
 | |
|     } else {
 | |
|         $realm = uc($domain);
 | |
|         $realm =~ s/\.$//; #remove trailing dot if provided
 | |
|     }
 | |
|     my $passtab = xCAT::Table->new('passwd');
 | |
|     my $adpent = $passtab->getAttribs({key=>'activedirectory'},[qw/username password/]);
 | |
|     unless ($adpent and $adpent->{username} and $adpent->{password}) {
 | |
|         sendmsg([1,"activedirectory entry missing from passwd table"]);
 | |
|         return 1;
 | |
|     }
 | |
|     if ($server and $server->{value}) {
 | |
|         $server = $server->{value};
 | |
|     } else {
 | |
|         my $res = Net::DNS::Resolver->new;
 | |
|         my $query = $res->query("_ldap._tcp.$domain","SRV");
 | |
|         if ($query) {
 | |
|             foreach my $srec ($query->answer) {
 | |
|                 $server = $srec->{target};
 | |
|             }
 | |
|         }
 | |
|         unless ($server) {
 | |
|             sendmsg([1,"Unable to determine a directory server to communicate with, try site.directoryserver"]);
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     if ($command =~ /userlist/) { #user management command, listing
 | |
|         my $passwdfmt;
 | |
|         if ($request->{arg}) {
 | |
|             @ARGV=@{$request->{arg}};
 | |
|             Getopt::Long::Configure("bundling");
 | |
|             Getopt::Long::Configure("no_pass_through");
 | |
|             if (!GetOptions(
 | |
|                 'p' => \$passwdfmt
 | |
|                 )) {
 | |
|                 die "TODO: usage message";
 | |
|             }
 | |
|         }
 | |
|          unless ($domain and $realm) {
 | |
|              sendmsg([1,"Unable to determine domain from arguments or site table"]);
 | |
|              return undef;
 | |
|          }
 | |
|          my $err = xCAT::ADUtils::krb_login(username=>$adpent->{username},password=>$adpent->{password},realm=>$realm);
 | |
|          if ($err) {
 | |
|              sendmsg([1,"Error authenticating to Active Directory"]);
 | |
|              return 1;
 | |
|          }
 | |
|          my $accounts = xCAT::ADUtils::list_user_accounts(
 | |
|             dnsdomain => $domain,
 | |
|             directoryserver=> $server,
 | |
|          );
 | |
|          if ($passwdfmt) {
 | |
|              my $account;
 | |
|              foreach $account (keys %$accounts) {
 | |
|                  my $textout = ":".$account.":x:"; #first colon is because sendmsg would mistake it for a description
 | |
|                  foreach (qw/uid gid fullname homedir shell/) {
 | |
|                      $textout .= $accounts->{$account}->{$_}.":";
 | |
|                  }
 | |
|                  $textout =~ s/:$//;
 | |
|                  sendmsg($textout);
 | |
|              }
 | |
|          } else {
 | |
|              my $account;
 | |
|              foreach $account (keys %$accounts) {
 | |
|                  sendmsg($account);
 | |
|              }
 | |
|          }
 | |
|     } elsif ($command =~ /hostaccountlist/) {
 | |
|          unless ($domain and $realm) {
 | |
|              sendmsg([1,"Unable to determine domain from arguments or site table"]);
 | |
|              return undef;
 | |
|          }
 | |
|          my $err = xCAT::ADUtils::krb_login(username=>$adpent->{username},password=>$adpent->{password},realm=>$realm);
 | |
|          if ($err) {
 | |
|              sendmsg([1,"Error authenticating to Active Directory"]);
 | |
|              return 1;
 | |
|          }
 | |
|          my $accounts = xCAT::ADUtils::list_host_accounts(
 | |
|             dnsdomain => $domain,
 | |
|             directoryserver=> $server,
 | |
|          );
 | |
|          my $account;
 | |
|          foreach $account (keys %$accounts) {
 | |
|              sendmsg($account);
 | |
|          }
 | |
|     } elsif ($command =~ /hostaccountdel/) {
 | |
|          my $accountname;
 | |
|          my %loggedrealms = ();
 | |
|          foreach $accountname (@{$request->{node}}) {
 | |
|              if ($request->{arg} and scalar @{$request->{arg}}) {
 | |
|                  die "TODO: usage";
 | |
|              }
 | |
|              if ($accountname =~ /@/) {
 | |
|                  ($accountname,$domain) = split /@/,$accountname;
 | |
|                  $domain = lc($domain);
 | |
|              } 
 | |
|               unless ($domain) {
 | |
|                  sendmsg([1,"Unable to determine domain from arguments or site table"]);
 | |
|                  return undef;
 | |
|              }
 | |
|              #my $domainstab = xCAT::Table->new('domains');
 | |
|              #$realm = $domainstab->getAttribs({domain=>$domain},
 | |
|              unless ($realm) {
 | |
|                 $realm = uc($domain);
 | |
|                 $realm =~ s/\.$//; #remove trailing dot if provided
 | |
|              }
 | |
|              $ENV{KRB5CCNAME}="/tmp/xcat/krbcache.$realm.$$";
 | |
|              unless ($loggedrealms{$realm}) {
 | |
|                 my $err = xCAT::ADUtils::krb_login(username=>$adpent->{username},password=>$adpent->{password},realm=>$realm);
 | |
|                  if ($err) {
 | |
|                      sendmsg([1,"Error authenticating to Active Directory"],$accountname);
 | |
|                      next;
 | |
|                  }
 | |
|                  $loggedrealms{$realm}=1;
 | |
|              }
 | |
|              my %args = (
 | |
|                 account => $accountname,
 | |
|                 dnsdomain => $domain,
 | |
|                 directoryserver=> $server,
 | |
|                 );
 | |
|              my $ret = xCAT::ADUtils::del_host_account(%args);
 | |
|          }
 | |
|          foreach my $realm (keys %loggedrealms) {
 | |
|              unlink "/tmp/xcat/krbcache.$realm.$$";
 | |
|          }
 | |
|     } elsif ($command =~ /userdel/) {
 | |
|         my $username = shift @{$request->{arg}};
 | |
|          if (scalar @{$request->{arg}}) {
 | |
|              die "TODO: usage";
 | |
|          }
 | |
|          if ($username =~ /@/) {
 | |
|              ($username,$domain) = split /@/,$username;
 | |
|              $domain = lc($domain);
 | |
|          } 
 | |
|          unless ($domain) {
 | |
|              sendmsg([1,"Unable to determine domain from arguments or site table"]);
 | |
|              return undef;
 | |
|          }
 | |
| 
 | |
|          #my $domainstab = xCAT::Table->new('domains');
 | |
|          #$realm = $domainstab->getAttribs({domain=>$domain},
 | |
|          unless ($realm) {
 | |
|             $realm = uc($domain);
 | |
|             $realm =~ s/\.$//; #remove trailing dot if provided
 | |
|          }
 | |
|          $ENV{KRB5CCNAME}="/tmp/xcat/krbcache.$realm.$$";
 | |
| 
 | |
|          my $err = xCAT::ADUtils::krb_login(username=>$adpent->{username},password=>$adpent->{password},realm=>$realm);
 | |
|          if ($err) {
 | |
|              sendmsg([1,"Error authenticating to Active Directory"]);
 | |
|              return 1;
 | |
|          }
 | |
|          my %args = (
 | |
|                 account => $username,
 | |
|                 dnsdomain => $domain,
 | |
|                 directoryserver=> $server,
 | |
|                 );
 | |
|          if ($command =~ /userdel/) {
 | |
|              my $ret = xCAT::ADUtils::del_user_account(%args);
 | |
|          } elsif ($command =~ /hostaccountdel/) {
 | |
|              my $ret = xCAT::ADUtils::del_host_account(%args);
 | |
|          }
 | |
|     } elsif ($command =~ /useradd$/) { #user management command, adding
 | |
|         my $homedir;
 | |
|         my $fullname;
 | |
|         my $gid;
 | |
|         my $uid;
 | |
|         my $ou;
 | |
|         @ARGV=@{$request->{arg}};
 | |
|         Getopt::Long::Configure("bundling");
 | |
|         Getopt::Long::Configure("no_pass_through");
 | |
| 
 | |
|          if (!GetOptions(
 | |
|             'd=s' => \$homedir,
 | |
|             'c=s' => \$fullname,
 | |
|             'g=s' => \$gid,
 | |
|             'o=s' => \$ou,
 | |
|             'u=s' => \$uid)) {
 | |
|              die "TODO: usage message";
 | |
|          }
 | |
|          my $username = shift @ARGV;
 | |
|          if ($username =~ /@/) {
 | |
|              ($username,$domain) = split /@/,$username;
 | |
|              $domain = lc($domain);
 | |
|          } 
 | |
|          unless ($domain) {
 | |
|              sendmsg([1,"Unable to determine domain from arguments or site table"]);
 | |
|              return undef;
 | |
|          }
 | |
| 
 | |
|          #my $domainstab = xCAT::Table->new('domains');
 | |
|          #$realm = $domainstab->getAttribs({domain=>$domain},
 | |
|          unless ($realm) {
 | |
|             $realm = uc($domain);
 | |
|             $realm =~ s/\.$//; #remove trailing dot if provided
 | |
|          }
 | |
| 
 | |
|          my $err = xCAT::ADUtils::krb_login(username=>$adpent->{username},password=>$adpent->{password},realm=>$realm);
 | |
|          if ($err) {
 | |
|              sendmsg([1,"Error authenticating to Active Directory"]);
 | |
|              return 1;
 | |
|          }
 | |
|          my %args = ( 
 | |
|             username => $username,
 | |
|             dnsdomain => $domain,
 | |
|             directoryserver=> $server,
 | |
|          );
 | |
|          if ($fullname) { $args{fullname} = $fullname };
 | |
|          if ($ou)  { $args{ou} = $ou };
 | |
|          if ($request->{environment} and 
 | |
|              $request->{environment}->[0]->{XCAT_USERPASS}) {
 | |
|              $args{password} = $request->{environment}->[0]->{XCAT_USERPASS}->[0];
 | |
|          }
 | |
|         #TODO: args password
 | |
|          if (defined $gid) { $args{gid} = $gid };
 | |
|          if (defined $uid) { $args{uid} = $uid };
 | |
|         #TODO: smbHome for windows
 | |
|          if (defined $homedir) { $args{homedir} = $homedir };
 | |
|          my $ret = xCAT::ADUtils::add_user_account(%args);
 | |
|          if (ref $ret and $ret->{error}) {
 | |
|              sendmsg([1,$ret->{error}]);
 | |
|          }
 | |
|     } elsif ($command =~ /hostaccountadd$/) { #user management command, adding
 | |
|         my $ou;
 | |
|         if ($request->{arg}) {
 | |
|             @ARGV=@{$request->{arg}};
 | |
|             Getopt::Long::Configure("bundling");
 | |
|             Getopt::Long::Configure("no_pass_through");
 | |
|     
 | |
|             if (!GetOptions('o=s' => \$ou)) {
 | |
|                 die "TODO: usage message";
 | |
|             }
 | |
|         }
 | |
|         #my $domainents = $domaintab->getNodesAttribs($request->{node},['ou','domain']); #TODO: have this in schema
 | |
|         my $nodename;
 | |
|         my %loggedrealms=();
 | |
|         foreach $nodename (@{$request->{node}}) {
 | |
|           if ($nodename =~ /\./) {
 | |
|                  ($nodename,$domain) = split /\./,$nodename,2;
 | |
|                  $domain = lc($domain);
 | |
|              } 
 | |
|              unless ($domain) {
 | |
|                  sendmsg([1,"Unable to determine domain from arguments or site table"]);
 | |
|                  return undef;
 | |
|              }
 | |
|     
 | |
|              #my $domainstab = xCAT::Table->new('domains');
 | |
|              #$realm = $domainstab->getAttribs({domain=>$domain},
 | |
|              unless ($realm) {
 | |
|                 $realm = uc($domain);
 | |
|                 $realm =~ s/\.$//; #remove trailing dot if provided
 | |
|              }
 | |
|              unless ($loggedrealms{$realm}) {
 | |
|                 my $err = xCAT::ADUtils::krb_login(username=>$adpent->{username},password=>$adpent->{password},realm=>$realm);
 | |
|                  if ($err) {
 | |
|                      sendmsg([1,"Error authenticating to Active Directory"],$nodename);
 | |
|                      next;
 | |
|                  }
 | |
|                  $loggedrealms{$realm}=1;
 | |
|              }
 | |
|     
 | |
|              my %args = ( 
 | |
|                 node => $nodename,
 | |
|                 dnsdomain => $domain,
 | |
|                 directoryserver=> $server,
 | |
|              );
 | |
|              if ($ou)  { $args{ou} = $ou };
 | |
|              if ($request->{environment} and 
 | |
|                  $request->{environment}->[0]->{XCAT_HOSTPASS}) {
 | |
|                  $args{password} = $request->{environment}->[0]->{XCAT_HOSTPASS}->[0];
 | |
|              }
 | |
|              my $ret = xCAT::ADUtils::add_host_account(%args);
 | |
|              if (ref $ret and $ret->{error}) {
 | |
|                  sendmsg([1,$ret->{error}]);
 | |
|              } elsif (ref $ret)  {
 | |
|                  sendmsg($ret->{password},$nodename);
 | |
|              }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| sub sendmsg {
 | |
|     my $text = shift;
 | |
|     my $node = shift;
 | |
|     my $descr;
 | |
|     my $rc;
 | |
|     if (ref $text eq 'HASH') {
 | |
|         die "not right now";
 | |
|     } elsif (ref $text eq 'ARRAY') {
 | |
|         $rc = $text->[0];
 | |
|         $text = $text->[1];
 | |
|     }
 | |
|     if ($text =~ /:/) {
 | |
|         ($descr,$text) = split /:/,$text,2;
 | |
|     }
 | |
|     $text =~ s/^ *//;
 | |
|     $text =~ s/ *$//;
 | |
|     my $msg;
 | |
|     my $curptr;
 | |
|     if ($node) {
 | |
|         $msg->{node}=[{name => [$node]}];
 | |
|         $curptr=$msg->{node}->[0];
 | |
|     } else {
 | |
|         $msg = {};
 | |
|         $curptr = $msg;
 | |
|     }
 | |
|     if ($rc) {
 | |
|         $curptr->{errorcode}=[$rc];
 | |
|         $curptr->{error}=[$text];
 | |
|         $curptr=$curptr->{error}->[0];
 | |
|     } else {
 | |
|         $curptr->{data}=[{contents=>[$text]}];
 | |
|         $curptr=$curptr->{data}->[0];
 | |
|         if ($descr) { $curptr->{desc}=[$descr]; }
 | |
|     }
 | |
| #        print $outfd freeze([$msg]);
 | |
| #        print $outfd "\nENDOFFREEZE6sK4ci\n";
 | |
| #        yield;
 | |
| #        waitforack($outfd);
 | |
|     $callback->($msg);
 | |
| }
 | |
| 1;
 |