-Allow windows templates to auto-acquire machine account passwords for first boot without divulging credentials to deployed systems
git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@5427 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
parent
2b43b7e935
commit
25e9583010
@ -56,17 +56,19 @@ statelite => {
|
||||
#tables come into play. Given no explicit request to span domains and no effort to
|
||||
#seriously evaluate wider support of multi-domain environments, will leave them
|
||||
#commented rather than tempt people to try with an expectation that it could work.
|
||||
#domain => {
|
||||
# cols => [qw(node domain comments disable)],
|
||||
# keys => ['node'],
|
||||
# table_desc => 'Mapping of nodes to domains',
|
||||
# descriptions => {
|
||||
# node => 'The node or group the entry applies to',
|
||||
domain => {
|
||||
cols => [qw(node ou comments disable)],
|
||||
keys => ['node'],
|
||||
table_desc => 'Mapping of nodes to domain attributes',
|
||||
descriptions => {
|
||||
node => 'The node or group the entry applies to',
|
||||
# domain => 'The name of the domain it is a member of, such as "example.com". Defaults to domain value from the site table',
|
||||
# comments => 'Any user-written notes.',
|
||||
# disable => "Set to 'yes' or '1' to comment out this row.",
|
||||
# },
|
||||
#},
|
||||
# the above column is unimplemented by anything, so leave it out for this pass
|
||||
ou => 'For an LDAP described machine account (i.e. Active Directory), the orginaztional unit to place the system. If not set, defaults to cn=Computers,dc=your,dc=domain',
|
||||
comments => 'Any user-written notes.',
|
||||
disable => "Set to 'yes' or '1' to comment out this row.",
|
||||
},
|
||||
},
|
||||
#domains => {
|
||||
# cols => [qw(domain nameserver authserver realm comments disable)],
|
||||
# keys => ['domain'],
|
||||
|
@ -8,6 +8,11 @@ use File::Basename;
|
||||
use File::Path;
|
||||
use Data::Dumper;
|
||||
use Sys::Syslog;
|
||||
use xCAT::ADUtils; #to allow setting of one-time machine passwords
|
||||
my $netdnssupport = eval {
|
||||
require Net::DNS;
|
||||
1;
|
||||
};
|
||||
|
||||
my $tmplerr;
|
||||
my $table;
|
||||
@ -15,6 +20,7 @@ my $key;
|
||||
my $field;
|
||||
my $idir;
|
||||
my $node;
|
||||
my %loggedrealms;
|
||||
|
||||
sub subvars {
|
||||
my $self = shift;
|
||||
@ -70,6 +76,7 @@ sub subvars {
|
||||
#ok, now do everything else..
|
||||
$inc =~ s/#XCATVAR:([^#]+)#/envvar($1)/eg;
|
||||
$inc =~ s/#ENV:([^#]+)#/envvar($1)/eg;
|
||||
$inc =~ s/#MACHINEPASSWORD#/machinepassword()/eg;
|
||||
$inc =~ s/#TABLE:([^:]+):([^:]+):([^#]+)#/tabdb($1,$2,$3)/eg;
|
||||
$inc =~ s/#TABLEBLANKOKAY:([^:]+):([^:]+):([^#]+)#/tabdb($1,$2,$3,'1')/eg;
|
||||
$inc =~ s/#CRYPT:([^:]+):([^:]+):([^#]+)#/crydb($1,$2,$3)/eg;
|
||||
@ -86,6 +93,78 @@ sub subvars {
|
||||
close($outh);
|
||||
return 0;
|
||||
}
|
||||
sub machinepassword {
|
||||
my $domaintab = xCAT::Table->new('domain');
|
||||
$ENV{LDAPCONF}='/etc/xcat/ad.ldaprc';
|
||||
my $ou;
|
||||
if ($domaintab) {
|
||||
my $ouent = $domaintab->getNodeAttribs('node','ou');
|
||||
if ($ouent and $ouent->{ou}) {
|
||||
$ou = $ouent->{ou};
|
||||
}
|
||||
}
|
||||
my $sitetab = xCAT::Table->new('site');
|
||||
unless ($sitetab) {
|
||||
return "ERROR: unable to open site table";
|
||||
}
|
||||
my $domain;
|
||||
(my $et) = $sitetab->getAttribs({key=>"domain"},'value');
|
||||
if ($et and $et->{value}) {
|
||||
$domain = $et->{value};
|
||||
}
|
||||
unless ($domain) {
|
||||
return "ERROR: no domain set in site table";
|
||||
}
|
||||
my $realm = uc($domain);
|
||||
$realm =~ s/\.$//;
|
||||
$realm =~ s/^\.//;
|
||||
$ENV{KRB5CCNAME}="/tmp/xcat/krbcache.$realm.$$";
|
||||
unless ($loggedrealms{$realm}) {
|
||||
my $passtab = xCAT::Table->new('passwd',-create=>0);
|
||||
unless ($passtab) { sendmsg([1,"Error authenticating to Active Directory"],$node); return; }
|
||||
(my $adpent) = $passtab->getAttribs({key=>'activedirectory'},['username','password']);
|
||||
unless ($adpent and $adpent->{username} and $adpent->{password}) {
|
||||
return "ERROR: activedirectory entry missing from passwd table";
|
||||
}
|
||||
my $err = xCAT::ADUtils::krb_login(username=>$adpent->{username},password=>$adpent->{password},realm=>$realm);
|
||||
if ($err) {
|
||||
return "ERROR: authenticating to Active Directory";
|
||||
}
|
||||
$loggedrealms{$realm}=1;
|
||||
}
|
||||
my $server = $sitetab->getAttribs({key=>'directoryserver'},['value']);
|
||||
if ($server and $server->{value}) {
|
||||
$server = $server->{value};
|
||||
} else {
|
||||
$server = '';
|
||||
if ($netdnssupport) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
my %args = (
|
||||
node => $node,
|
||||
dnsdomain => $domain,
|
||||
directoryserver => $server,
|
||||
changepassondupe => 1,
|
||||
);
|
||||
if ($ou) { $args{ou} = $ou };
|
||||
my $data = xCAT::ADUtils::add_host_account(%args);
|
||||
if ($data->{error}) {
|
||||
return "ERROR: ".$data->{error};
|
||||
} else {
|
||||
return $data->{password};
|
||||
}
|
||||
}
|
||||
sub includefile
|
||||
{
|
||||
my $file = shift;
|
||||
@ -95,8 +174,7 @@ sub includefile
|
||||
$file = $idir."/".$file;
|
||||
}
|
||||
|
||||
open(INCLUDE,$file) || \
|
||||
return "#INCLUDEBAD:cannot open $file#";
|
||||
open(INCLUDE,$file) || return "#INCLUDEBAD:cannot open $file#";
|
||||
|
||||
while(<INCLUDE>) {
|
||||
$text .= "$_";
|
||||
|
@ -41,6 +41,12 @@ dn: CN=##NODENAME##,##OU##
|
||||
changetype: modify
|
||||
replace: unicodePwd
|
||||
unicodePwd::##B64PASSWORD##';
|
||||
|
||||
my $machineldifpasschange = 'dn: CN=##NODENAME##,##OU##
|
||||
changetype: modify
|
||||
replace: unicodePwd
|
||||
unicodePwd::##B64PASSWORD##';
|
||||
|
||||
my $useraccounttemplate = 'dn: CN=##FULLNAME##,##OU##
|
||||
changetype: add
|
||||
objectClass: top
|
||||
@ -466,6 +472,7 @@ sub add_host_account {
|
||||
my %args = @_;
|
||||
my $nodename = $args{node};
|
||||
my $dnsdomain = $args{dnsdomain};
|
||||
my $changepassondupe = $args{changepassondupe};
|
||||
if (not $dnsdomain and $nodename =~ /\./) { #if no domain provided, guess from nodename
|
||||
$dnsdomain = $nodename;
|
||||
$dnsdomain =~ s/^[^\.]*//;
|
||||
@ -492,28 +499,37 @@ sub add_host_account {
|
||||
return {error=>"Unable to determine all required parameters"};
|
||||
}
|
||||
my $newpassword = $args{password};
|
||||
unless ($newpassword) {
|
||||
$newpassword = '"'.genpassword(8).'"';
|
||||
if ($newpassword) {
|
||||
$newpassword = '"'.$newpassword.'"';
|
||||
} else {
|
||||
$newpassword = '"'.genpassword(8).'a0P"'; #add a little to assure that a fluke doesn't produce a password that won't pass MS filters
|
||||
}
|
||||
my $nativenewpassword = $newpassword;
|
||||
Encode::from_to($newpassword,"utf8","utf16le"); #ms uses utf16le, we use utf8
|
||||
my $b64password = encode_base64($newpassword);
|
||||
my $ldif = $machineldiftemplate;
|
||||
my $ldif;
|
||||
my $dn = "CN=$nodename,$ou";
|
||||
my $rc = system("ldapsearch -H ldaps://$directoryserver -b $dn"); #TODO: for mass add, search once, hit that
|
||||
if ($rc == 0) {
|
||||
if ($changepassondupe) {
|
||||
$ldif = $machineldifpasschange;
|
||||
} else {
|
||||
return {error=>"System already exists"};
|
||||
}
|
||||
} elsif (not $rc==8192) {
|
||||
return {error=>"Unknown error $rc"};
|
||||
} else {
|
||||
$ldif = $machineldiftemplate;
|
||||
}
|
||||
$ldif =~ s/##B64PASSWORD##/$b64password/g;
|
||||
$ldif =~ s/##OU##/$ou/g;
|
||||
$ldif =~ s/##REALMDCS##/$domain_components/g;
|
||||
$ldif =~ s/##DNSDOMAIN##/$dnsdomain/g;
|
||||
$ldif =~ s/##NODENAME##/$nodename/g;
|
||||
my $dn = "CN=$nodename,$ou";
|
||||
my $rc = system("ldapsearch -H ldaps://$directoryserver -b $dn");
|
||||
if ($rc == 0) {
|
||||
return {error=>"System already exists"};
|
||||
} elsif (not $rc==8192) {
|
||||
return {error=>"Unknown error $rc"};
|
||||
}
|
||||
open(HUH,">","/tmp/huhh");
|
||||
print HUH $ldif;
|
||||
$rc = system("echo '$ldif'|ldapmodify -H ldaps://$directoryserver");
|
||||
return {password=>$newpassword};
|
||||
substr $nativenewpassword,0,1,'';
|
||||
chop($nativenewpassword);
|
||||
return {password=>$nativenewpassword};
|
||||
}
|
||||
|
||||
sub krb_login {
|
||||
|
Loading…
Reference in New Issue
Block a user