Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- #
- # dl2groups.py A script to automatic mirroring of Zimbra distribution
- # lists to classical LDAP groups structure.
- #
- #This script based on script written by Carlos Vidal <[email protected]>
- #and found on Zimbra support forum
- #
- #
- HELP = "\
- Usage: zdl2groups [flags]\n\
- \n\
- This command connects to Zimbra's LDAP server and creates classical LDAP groups according all existing Distribution Lists.\n\
- It's quite useful for connecting 3rd party sw like Alfresco or Openfire Jabber Server.\n\
- \n\
- Parameters: \n\
- -a, --add :add group CN records according DistributionLists \n\
- -d, --del :remove all existing group CN records \n\
- -p, --print : print proposed changes\n\
- \n\
- \n\
- -u=name, --user=name :LDAP login as uid=name,cn=admins,cn=zimbra\n\
- :defaulf login is uid=zimbra,cn=admins,cn=zimbra \n\
- -p=, --pass=, --passwd=, password= :LDAP password\n\
- -b=, --base= :LDAP search base\n\
- -h, --help : this help screen message\n\
- -l, --list :list possible changes (for tesing)\n\
- \n\
- use -l, -l -d, -a, -d , -a -d\n\
- "
- LDAP_SERVER = 'ldap://m.hansa.com.ua:389'
- #LDAP_BASE = 'dc=com,dc=ua'
- LDAP_BASE = 'dc=ua'
- LDAP_USER = 'uid=zimbra,cn=admins,cn=zimbra'
- LDAP_PASS = 'password' #use in terminal zmlocalconfig -s -m nokey zimbra_ldap_password
- OUT_FILE = '/tmp/updategroups.zm'
- MAIL = ''
- # LDAP_USER=''
- # LDAP_PASS=''
- import getopt
- import sys
- import ldap
- class Person:
- #re_groups = re.compile(".*groupe?s:(.*)", re.M | re.I)
- def __init__(self, mail):
- self.mail = mail
- self.alias = []
- self.dn = ''
- self.sn = ''
- self.givenName = ''
- self.displayName = ''
- self.zimbraNotes = ''
- self.description = ''
- self.co = ''
- self.company = ''
- class Group:
- def __init__(self, mail):
- self.dn = ''
- self.gdn = ''
- self.mail = mail
- self.alias = []
- self.members = []
- self.realmembers = []
- self.cn=''
- self.description=''
- self.zimbraNotes=''
- self.ldif=''
- def getListsData(l):
- allGroups.clear()
- # Get all DLs by LDAP search
- for dn, g in l.search_s(LDAP_BASE, ldap.SCOPE_SUBTREE, "ObjectClass=zimbraDistributionList"):
- #print dn
- if 'mail' in g:
- grp = Group(g['mail'][0])
- grp.alias = g['mail'][1:]
- grp.dn = dn
- #convert list dn like uid=grp_name, ou=peole to gdn (like cn=list_name,ou=people,dc=domain,dc=com )
- grp.gdn = dn.replace(',ou=people,',',ou=groups,').replace('uid=','cn=')
- if 'cn' in g: grp.cn = g['cn']
- if 'description' in g: grp.description = g['description']
- if 'zimbraNotes' in g: grp.zimbraNotes = g['zimbraNotes']
- else:
- continue
- if 'zimbraMailForwardingAddress' in g:
- grp.members = g['zimbraMailForwardingAddress']
- allGroups[grp.mail] = grp
- def getPersonsData(l):
- allPersons.clear()
- # Get all persons and their description fields
- for dn, p in l.search_s(LDAP_BASE, ldap.SCOPE_SUBTREE,"(&(objectClass=organizationalPerson)(zimbraMailStatus=enabled)(zimbraAccountStatus=active)(!(|(uid=wiki)(uid=admin)(uid=spam.*)(uid=ham.*)(uid=galsync))))"):
- #print p,"\n"
- if 'zimbraMailDeliveryAddress' in p:
- per = Person(p['zimbraMailDeliveryAddress'][0])
- per.alias = p['mail']
- per.dn = dn
- if 'cn' in p: per.cn = p['cn']
- if 'givenName' in p: per.givenName = p['givenName'][0].strip()
- if 'sn' in p: per.sn = p['sn'][0].strip()
- if 'displayName' in p: per.displayName = p['displayName'][0]
- if 'zimbraNotes' in p: per.zimbraNotes = p['zimbraNotes'][0]
- if 'description' in p: per.description = p['description'][0]
- if 'co' in p: per.co = p['co'][0]
- if 'company' in p: per.company = p['company'][0]
- else:
- continue
- allPersons[per.mail] = per
- def resolveDLUsers(grp):
- # this function resolves members like alias or another list and returns sorted list of real users (those main mails) w/o duplicates
- realmembers = []
- #print "\nProgessing group ",grp.mail,'members:', grp.members
- for addr in grp.members:
- if addr in allPersons:
- if addr in allPersons[addr].mail:
- #print addr, 'It is a real acc'
- realmembers.append (addr)
- continue
- elif addr in allGroups:
- if addr in allGroups[addr].mail:
- #print addr, ' Its a list. We have to expand it.'
- for z in resolveDLUsers(allGroups[addr]):
- realmembers.append(z)
- continue
- else:
- for g in allGroups:
- if addr in allGroups[g].alias:
- #print addr, "Group alias. Will be expanded ", allGroups[g].mail
- for z in resolveDLUsers(allGroups[allGroups[g].mail]):
- realmembers.append(z)
- continue
- for m in allPersons:
- if addr in allPersons[m].alias:
- #print addr, "Users alias. Real account is ",allPersons[m].mail
- realmembers.append(allPersons[m].mail)
- continue
- #sort and remove duplicates
- if realmembers:
- realmembers.sort()
- last=realmembers[-1]
- for i in range(len(realmembers)-2, -1, -1):
- if last==realmembers[i]: del realmembers[i]
- else: last=realmembers[i]
- grp.realmembers=realmembers
- return realmembers
- # this functions checks if required ou=groups leafs exist for zimbra domains
- def getRequiredOuGroupsDNs(l):
- # Get all DNs for ou=people for all domains and subdomains
- res=[]
- for dn, p in l.search_s(LDAP_BASE, ldap.SCOPE_SUBTREE,"(ou=people)"):
- res.append(dn.replace('ou=people,','ou=groups,'))
- return res
- def getExistingOuGroupsDNs(l):
- # Get all DNs for ou=groups for all domains and subdomains
- res=[]
- for dn, p in l.search_s(LDAP_BASE, ldap.SCOPE_SUBTREE,"(ou=groups)"):
- res.append(dn)
- return res
- def createOuGroupsDN(l,d):
- add_record = [ ('objectClass', ['top','organizationalUnit']), ('ou', ['groups']) ]
- try:
- l.add_s(d, add_record)
- except ldap.LDAPError, e:
- print ' createOuGroupsDN: error for ', d
- if type(e.message) == dict and e.message.has_key('desc'):
- print 'Error - ' + e.message['desc']
- else:
- print 'Error - ' + str(e)
- def deleteOuGroupsDN(l,d):
- try:
- l.delete_s(d)
- except ldap.LDAPError, e:
- print ' deleteOuGroupsDN: error for ', d
- if type(e.message) == dict and e.message.has_key('desc'):
- print 'Error - ' + e.message['desc']
- else:
- print 'Error - ' + str(e)
- # this function checks is certain groups CN exists
- def existCnGroup(l,grp):
- gdn=allGroups[grp].gdn
- try:
- l.search_s(gdn, ldap.SCOPE_SUBTREE,"(objectClass=*)")
- return 1
- except ldap.LDAPError, e:
- return 0
- def getExistingCnGroup(l):
- # Get all DNs for ou=groups for all domains and subdomains
- res=[]
- for dn, p in l.search_s(LDAP_BASE, ldap.SCOPE_SUBTREE,"(objectClass=groupOfNames)"):
- res.append(dn)
- return res
- def createCnGroup(l,grp,members):
- if len(members):
- #convert group mail=grp to gdn (like cn=list_name,ou=people,dc=domain,dc=com )
- gdn=allGroups[grp].gdn
- #print ' Processing ',grp, ' will create CN record ', gdn
- dnmembers=[]
- for memb in members:
- dnmembers.append(allPersons[memb].dn)
- add_record = [ ('objectClass', ['top','groupOfNames']), ('member',dnmembers)]
- if len(allGroups[grp].description):
- add_record.append(('description',allGroups[grp].description))
- if len(allGroups[grp].cn):
- add_record.append(('o',allGroups[grp].cn))
- try:
- l.add_s(gdn, add_record)
- except ldap.LDAPError, e:
- print ' createCnGroup: error for ', gdn
- if type(e.message) == dict and e.message.has_key('desc'):
- print 'Error - ' + e.message['desc']
- else:
- print 'Error - ' + str(e)
- #delete certain groups by it's corresponding DL's email
- def deleteCnGroupByMail(l,grp):
- #convert group mail=grp to gdn (like cn=list_name,ou=people,dc=domain,dc=com )
- gdn=allGroups[grp].gdn
- #print " deleteCnGroupByMail: will be deleted ",gdn
- try:
- l.delete_s(gdn)
- return 0
- except ldap.LDAPError, e:
- if type(e.message) == dict and e.message.has_key('desc'):
- #print 'Error - ' + e.message['desc']
- return e.message['desc']
- else:
- #print 'Unknown error - ' + str(e)
- return str(e)
- #--------------------------- M A I N ---------------------------
- allPersons = {}
- allGroups = {}
- if __name__ == '__main__':
- # Parse command line options
- # If a program wants to take 2 options, -a, and -b with the b option requiring an argument, the value should be "ab:".
- try:
- opts, args = getopt.getopt(sys.argv[1:], 'hadls:u:p:b:', ['help', 'del', 'list', 'server=', 'user=', 'password=', 'passwd=', 'pass=', 'base='])
- except:
- print "Wrong parameters.\n"
- print HELP
- sys.exit(1)
- listp = 0
- addp = 0
- delp = 0
- if len(opts) > 0 :
- for o, a in opts:
- if o in ('-l', '--list'):
- listp = 1
- elif o in ('-d', '--del'):
- delp = 1
- elif o in ('-a', '--add'):
- addp = 1
- elif o in ('-l', '--list'):
- listp = 1
- elif o in ('-s', '--server'):
- LDAP_SERVER = a
- elif o in ('-u', '--user'):
- LDAP_USER = 'uid=%s,cn=admins,cn=zimbra' % a
- elif o in ('-p', '--pass', '--passwd', '--password'):
- LDAP_PASS = a
- elif o in ('-b', '--base'):
- LDAP_BASE = a
- else:
- print "Something is wrong in arguments.\n"
- #print HELP
- sys.exit(0)
- else:
- print "No arguments given.\n"
- print HELP
- sys.exit(0)
- # Connect to the LDAP server
- try:
- l = ldap.initialize(LDAP_SERVER)
- l.simple_bind_s(LDAP_USER, LDAP_PASS)
- except:
- print 'Cannot connect to LDAP server ' + LDAP_SERVER
- sys.exit(1)
- # Get the list of all DLs
- getListsData(l)
- getPersonsData(l)
- #del l
- # Normalize ou=groups leafs
- # ou=groups magic is here
- existGroupsDNs = getExistingOuGroupsDNs (l)
- existGroupsDNs.sort()
- #print '\n Exists in Zimbra ou-groups DNs:\n', existGroupsDNs
- reqGroupsDNs = getRequiredOuGroupsDNs (l)
- reqGroupsDNs.sort()
- #print " According Zimbra DistributionLists we need following group DNs:\n", reqGroupsDNs
- # create if need additional Groups DNs
- for d in reqGroupsDNs:
- if d not in existGroupsDNs:
- print '\nGroups DN: we have to create ', d
- if not listp:
- createOuGroupsDN(l,d)
- # delete unused Groups DNs
- for d in existGroupsDNs:
- if d not in reqGroupsDNs:
- print '\nGroups DN: we have to delete ', d
- if not listp:
- deleteOuGroupsDN(l,d)
- # ==== main group CN section ========
- #remove group CNs from LDAP
- if delp:
- #get list of all group CNs from LDAP
- exist_grp_CNs = getExistingCnGroup(l)
- if not listp:
- print 'Removing all existing group CNs from LDAP'
- for g in exist_grp_CNs:
- if listp:
- print ' Delete CN: ',g
- else:
- try:
- l.delete_s(g)
- except ldap.LDAPError, e:
- if type(e.message) == dict and e.message.has_key('desc'):
- print 'Error - ' + e.message['desc']
- else:
- print 'Unknown error - ' + str(e)
- #add group CNs to LDAP according existing DistributionLists
- if addp and not listp:
- # Expanding DistributionList members
- print "Expanding and Processing DistributionLists and it's members "
- for grp in allGroups:
- realmembs = resolveDLUsers(allGroups[grp])
- createCnGroup(l,grp,realmembs)
- if listp:
- print '\nLDAP_BASE: ',LDAP_BASE
- print 'LDAP_SERVER: ',LDAP_SERVER
- print "\nIf you remove -l parameter this script will make following changes in LDAP groups:"
- print "DistributionList = Group (members) "
- for grp in allGroups:
- realmembs = resolveDLUsers(allGroups[grp])
- print grp,' = ', allGroups[grp].gdn
- for m in realmembs:
- print ' ',m, ' = ', allPersons[m].dn
- print
- print 'Done.'
- l.unbind_s()
- sys.exit(0)
Advertisement
Add Comment
Please, Sign In to add comment