Citrix Xenserver 5.6 can not join to a DSfW domain

  • 7008231
  • 29-Mar-2011
  • 27-Apr-2012

Environment

Novell Open Enterprise Server 2 SP1 (OES2SP1)
Novell Open Enterprise Server 2 SP2 (OES2SP2)
Novell Open Enterprise Server 2 SP3 (OES2SP3)

Domain Services for Windows
DSFW
Citrix Xenserver 5.6

Situation

With Citrix Xenserver 5.6 a new feature was added that allows the xenserver to join to a domain to provide remote management of Xenserver.

The Xenserver fails to join a DSfW domain.

Resolution

When the Xenserver is attempting to join the domain it reads five Password Policy related attributes in eDirectory.
Below are the five attributes:
  1. PasswordExpirationInterval
  2. PasswordMinimumLength
  3. nspmConfigurationOptions
  4. nspmMinPasswordLifetime
  5. pwdInHistory

Run the following script to make the attributes readable.  Copy and past the python script below into a text editor.  Save the file as a python script, e.g. modify_attr.py
If the script was created on a Windows workstation run dos2unix to ensure extra characters are removed.
e.g. dos2unix modify_attry.py
Make the script executable, e.g. chmod 755 modify_attr.py
Run the script and it will make the necessary attributes readable.  e.g. ./modify_attr.py

###########################################################################
#!/usr/bin/env python
import os
import commands
import random

#This Script will add ACLs for 5 Password Policy attributes namely
#1) PasswordExpirationInterval
#2) PasswordMinimumLength
#3) nspmConfigurationoptions
#4) nspmminPasswordlifetimE
#5) pwdInHistory

attr_already_exits = 20
effective_rights ={'PASSWORDEXPIRATIONINTERVAL': 3, 'PASSWORDMINIMUMLENGTH': 3,'NSPMCONFIGURATIONOPTIONS': 3, 'NSPMMINPASSWORDLIFETIME': 3, 'PWDINHISTORY': 3}
pwd_attrs = ['PASSWORDEXPIRATIONINTERVAL', 'PASSWORDMINIMUMLENGTH', 'NSPMCONFIGURATIONOPTIONS', 'NSPMMINPASSWORDLIFETIME', 'PWDINHISTORY']

#create a random file name
ldif_file_name  = '/tmp/' + 'modify_pwd_attr' + str(random.random()) + '.ldif'
ldif_delete_acl = '/tmp/' + 'delete_pwd_attr' + str(random.random()) + '.ldif'
cmd_mod = 'LDAPCONF=/etc/opt/novell/xad/openldap/ldap.conf ldapmodify -c -Y EXTERNAL -f '+ ldif_file_name
cmd_delete = 'LDAPCONF=/etc/opt/novell/xad/openldap/ldap.conf ldapmodify -c -Y EXTERNAL -f '+ ldif_delete_acl


def getDomainName():
    #do an ldapsearch and get the value of defaultNamingContext
    domain_name = ""
    cmd = 'LDAPCONF=/etc/opt/novell/xad/openldap/ldap.conf ldapsearch -LLL -Y EXTERNAL  -b "" -s base defaultNamingContext'
    commandOutput = commands.getstatusoutput(cmd)
    if commandOutput[0] != 0:
        print "Ldap Search Error:[",commandOutput[1],']'
    else:
        for obj in commandOutput[1].split('\n'):
            if obj.split(':')[0] == 'defaultNamingContext':
                domain_name = obj.split(':')[1].strip()
    return domain_name

def searchExistingAttrs(domain_name):
    #command to search for exising ACLs on "Domain Computers"
    delete_reqd = 0
    cmd_search = 'LDAPCONF=/etc/opt/novell/xad/openldap/ldap.conf ldapsearch -LLL -Y EXTERNAL  -b '+ domain_name +' -s base ACL | sed " /^ / {; H; d; }; /^ /! {; x; s/\\n //; }; " | grep "Domain Computers"'
    fileH = open(ldif_delete_acl,'w')
    fileH.write('dn: '+ domain_name +'\n')
    fileH.write('changetype: modify\n')
    fileH.write('delete: ACL\n')
    commandOutput = commands.getstatusoutput(cmd_search)
    if commandOutput[0] != 0:
        print 'No preexisting ACLs found during the search on "Domain Computers"'
    else:
        for obj in commandOutput[1].split('\n'):
            if obj.split(':')[0] == 'ACL':
                for attr in pwd_attrs:
                    if(obj.upper().find(attr) != -1):
                 rights_existing = int(obj.split(':')[1].split('#')[0])
                        if rights_existing != effective_rights[attr]:
              acl_rights = effective_rights[attr]
              effective_rights[attr] = acl_rights | rights_existing
       fileH.write('ACL: '+str(rights_existing)+'#subtree#cn=Domain Computers,cn=Users,'+ domain_name +'#'+attr+'\n')
       delete_reqd = 1
    fileH.close() 
    return delete_reqd

def deleteExistingAttrs(domain_name):
    #delete the attributes
    #run ldapmodify with the ldif file as an argument
    commandOutput = commands.getstatusoutput(cmd_delete)
    if commandOutput[0] != 0:
        print "Ldap Delete Error:[",commandOutput[1],']'
        raise Exception('Error in ldapdelete')
    os.system('rm -rf ' +ldif_delete_acl)
    return
   
def updateNewAttrs(domain_name):
    #create a random ldif file in /tmp dir
   
    fileHandle = open(ldif_file_name,'w')
    fileHandle.write('dn: '+ domain_name +'\n')
    fileHandle.write('changetype: modify\n')
    fileHandle.write('add: ACL\n')
    fileHandle.write('ACL: '+str(effective_rights['PASSWORDEXPIRATIONINTERVAL'])+'#subtree#cn=Domain Computers,cn=Users,'+ domain_name +'#PasswordExpirationInterval\n')
    fileHandle.write('\n');

    fileHandle.write('dn: '+ domain_name +'\n')
    fileHandle.write('changetype: modify\n')
    fileHandle.write('add: ACL\n')
    fileHandle.write('ACL: '+str(effective_rights['PASSWORDMINIMUMLENGTH'])+'#subtree#cn=Domain Computers,cn=Users,'+ domain_name +'#PasswordMinimumLength\n')
    fileHandle.write('\n');

    fileHandle.write('dn: '+ domain_name +'\n')
    fileHandle.write('changetype: modify\n')
    fileHandle.write('add: ACL\n')
    fileHandle.write('ACL: '+str(effective_rights['NSPMCONFIGURATIONOPTIONS'])+'#subtree#cn=Domain Computers,cn=Users,'+ domain_name +'#nspmConfigurationOptions\n')
    fileHandle.write('\n');

    fileHandle.write('dn: '+ domain_name +'\n')
    fileHandle.write('changetype: modify\n')
    fileHandle.write('add: ACL\n')
    fileHandle.write('ACL: '+str(effective_rights['NSPMMINPASSWORDLIFETIME'])+'#subtree#cn=Domain Computers,cn=Users,'+ domain_name +'#nspmMinPasswordLifetime\n')
    fileHandle.write('\n');

    fileHandle.write('dn: '+ domain_name +'\n')
    fileHandle.write('changetype: modify\n')
    fileHandle.write('add: ACL\n')
    fileHandle.write('ACL: '+str(effective_rights['PWDINHISTORY'])+'#subtree#cn=Domain Computers,cn=Users,'+ domain_name +'#pwdInHistory\n')
    fileHandle.write('\n');
    fileHandle.close()

    #run ldapmodify with the ldif file as an argument
    commandOutput = commands.getstatusoutput(cmd_mod)
    result = commandOutput[0]>> 8
   
    if result != 0 and result != attr_already_exits:
        print "Ldap Modify Error:[",commandOutput[1],']'
        raise Exception('Error in ldapmodify')
    os.system('rm -rf ' + ldif_file_name)
    print "Update Sucessful"
    return

# main starts here
try:
    domain_name = getDomainName()
    if searchExistingAttrs(domain_name):
        deleteExistingAttrs(domain_name)
    updateNewAttrs(domain_name)

except Exception,err:
    print "Update Failed:Cannot continue...Reason-->[",err,"]"
    os.system('rm -rf ' + ldif_file_name)