From 8c43db338a9935ba741c5be1c704de3f6800694e Mon Sep 17 00:00:00 2001 From: jbjohnso Date: Mon, 8 Mar 2010 17:25:31 +0000 Subject: [PATCH] -hostaccountadd/hostaccountdel/hostaccountlist git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@5401 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd --- xCAT-server/lib/perl/xCAT/ADUtils.pm | 131 ++++++++++++++- .../lib/xcat/plugins/activedirectory.pm | 153 ++++++++++++++++-- 2 files changed, 264 insertions(+), 20 deletions(-) diff --git a/xCAT-server/lib/perl/xCAT/ADUtils.pm b/xCAT-server/lib/perl/xCAT/ADUtils.pm index c2bf74e72..5799f1873 100644 --- a/xCAT-server/lib/perl/xCAT/ADUtils.pm +++ b/xCAT-server/lib/perl/xCAT/ADUtils.pm @@ -80,11 +80,81 @@ replace: userAccountControl userAccountControl: 512'; +sub del_host_account { + my %args = @_; + my $directoryserver = $args{directoryserver}; + my $dnsdomain = $args{dnsdomain}; + my $account = $args{account}; + unless ($dnsdomain and $directoryserver and $account) { + die "Invalid arguments $dnsdomain and $directoryserver and $account"; + } + my $domain_components = $dnsdomain; + $domain_components =~ s/^\.//; + $domain_components =~ s/\./,dc=/g; + $domain_components =~ s/^/dc=/; + my @searchcmd = qw/ldapsearch -H /; + push @searchcmd,"ldaps://$directoryserver","-b",$domain_components; + push @searchcmd,"(&(&(&(objectClass=user)(objectClass=computer))(!(isCriticalSystemObject=TRUE)))(name=$account))","dn"; + my $searchout; + my $searchin; + my $searcherr = gensym; + my $search = open3($searchin,$searchout,$searcherr,@searchcmd); + print $searchout; + print $searchin; + my $searchselect = IO::Select->new($searchout,$searcherr); + my @handles; + my $failure; + my $dn; + while (@handles = $searchselect->can_read()) { + foreach (@handles) { + my $line = <$_>; + print $line; + if (not defined $line) { + $searchselect->remove($_); + next; + } + print $line; + if ($_ == $searcherr) { + if ($line =~ /error/i or $line =~ /problem/i) { + return {error=>$line}; + } + } elsif ($line =~ /^dn: (.*)$/) { + if ($dn) { die "TODO: identify these cases, let xcat-user know this can happen"; } + $dn = $1; + } + } + } + my $ldif = "dn: $dn +changetype: delete"; + my $deletein; + my $deleteout; + my $deleteerr = gensym; + my $deletion = open3($deletein,$deleteout,$deleteerr,'ldapmodify','-H',"ldaps://$directoryserver"); + print $deletein $ldif."\n"; + close($deletein); + print $ldif; + my $delselect = IO::Select->new($deleteout,$deleteerr); + while (@handles = $delselect->can_read()) { + foreach (@handles) { + my $line = <$_>; + print $line; + if (not defined $line) { + $delselect->remove($_); + next; + } + if ($_ == $deleteerr) { + if ($line =~ /error/i or $line =~ /problem/i) { + return {error=> $line}; + } + } + } + } +} sub del_user_account { my %args = @_; my $directoryserver = $args{directoryserver}; my $dnsdomain = $args{dnsdomain}; - my $account = $args{username}; + my $account = $args{account}; unless ($dnsdomain and $directoryserver and $account) { die "Invalid arguments $dnsdomain and $directoryserver and $account"; } @@ -151,6 +221,61 @@ changetype: delete"; } } +sub list_host_accounts { #provide enough data to construct an /etc/passwd looking output + my %args = @_; + my $directoryserver = $args{directoryserver}; + my $dnsdomain = $args{dnsdomain}; + unless ($dnsdomain and $directoryserver) { + die "Invalid arguments"; + } + my $domain_components = $dnsdomain; + $domain_components =~ s/^\.//; + $domain_components =~ s/\./,dc=/g; + $domain_components =~ s/^/dc=/; + my @searchcmd = qw/ldapsearch -H /; + push @searchcmd,"ldaps://$directoryserver","-b",$domain_components; + push @searchcmd,qw/(&(&(objectClass=user)(objectClass=computer))(!(isCriticalSystemObject=TRUE))) name operatingSystem operatingSystemServicePack/; + my $searchout; + my $searchin; + my $searcherr = gensym; + my $search = open3($searchin,$searchout,$searcherr,@searchcmd); + my $searchselect = IO::Select->new($searchout,$searcherr); + my @handles; + my $failure; + my %currvalues =(); + my %acchash= (); + while (@handles = $searchselect->can_read()) { + foreach (@handles) { + my $line = <$_>; + if (not defined $line) { + $searchselect->remove($_); + next; + } + if ($_ == $searcherr) { + if ($line =~ /error/i or $line =~ /problem/i) { + print $line; + $failure=1; + } + } elsif ($line =~ /^dn: (.*)$/) { + foreach(keys %currvalues) { + $acchash{$currvalues{accountname}}->{$_} = $currvalues{$_}; + } + %currvalues=(); + } elsif ($line =~ /^name: (.*)$/) { + $currvalues{accountname} = $1; + } elsif ($line =~ /^OperatingSystem: (.*)$/) { + $currvalues{os} = $1; + } elsif ($line =~ /^OperatingSystemServicePack: (.*)$/) { + $currvalues{osservicepack} = $1; + } + } + } + if ($failure) { return undef; } + foreach(keys %currvalues) { + $acchash{$currvalues{accountname}}->{$_} = $currvalues{$_}; + } + return \%acchash; +} sub list_user_accounts { #provide enough data to construct an /etc/passwd looking output my %args = @_; my $directoryserver = $args{directoryserver}; @@ -333,11 +458,11 @@ sub add_user_account { return {password=>$newpassword}; } =cut -add_machine_account +add_host_account Arguments are in a hash: node=>name of machine to add =cut -sub add_machine_account { +sub add_host_account { my %args = @_; my $nodename = $args{node}; my $dnsdomain = $args{dnsdomain}; diff --git a/xCAT-server/lib/xcat/plugins/activedirectory.pm b/xCAT-server/lib/xcat/plugins/activedirectory.pm index eebc8aac9..f2b34a790 100644 --- a/xCAT-server/lib/xcat/plugins/activedirectory.pm +++ b/xCAT-server/lib/xcat/plugins/activedirectory.pm @@ -13,16 +13,17 @@ use strict; sub handled_commands { return { - addclusteruser => 'site:directoryprovider', - addclouduser => 'site:directoryprovider', - delclusteruser => 'site:directoryprovider', - delclouduser => 'site:directoryprovider', - listclusterusers => 'site:directoryprovider', - listcloudusers => 'site:directoryprovider', + clusteruseradd => 'site:directoryprovider', + clusteruserdel => 'site:directoryprovider', + clusteruserlist => 'site:directoryprovider', + hostaccountlist => 'site:directoryprovider', + hostaccountadd => 'site:directoryprovider', + hostaccountdel => 'site:directoryprovider', }; } sub process_request { + $ENV{LDAPCONF}='/etc/xcat/ad.ldaprc'; my $request = shift; my $command = $request->{command}->[0]; $callback = shift; @@ -66,7 +67,7 @@ sub process_request { return; } } - if ($command =~ /list.*user/) { #user management command, listing + if ($command =~ /userlist/) { #user management command, listing my $passwdfmt; if ($request->{arg}) { @ARGV=@{$request->{arg}}; @@ -107,8 +108,66 @@ sub process_request { sendmsg($account); } } - } elsif ($command =~ /del.*user/) { - my $username = shift @{$request->{arg}}; + } 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"; } @@ -127,18 +186,24 @@ sub process_request { $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 $ret = xCAT::ADUtils::del_user_account( - username => $username, - dnsdomain => $domain, - directoryserver=> $server, - ); - } elsif ($command =~ /add.*user/) { #user management command, adding + 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; @@ -198,9 +263,63 @@ sub process_request { 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) { + print $ret->{password}; + } + } } - - } sub sendmsg {