(Answer) (Category) OpenLDAP Faq-O-Matic : (Category) OpenLDAP Software FAQ : (Answer) How Do I Export Active Directory into OpenLDAP to emulate the Outlook Global Address List?
Note: This was done using Windows using the openldap 2.3.39 which came with the cygwin distribution, skip the "Software Required" section if you are on unix and use a different guide instead!

Software Required:

Windows 2000, XP or 2003
SRVANY.EXE (from the Resource Kit)
INSTSVR.EXE (from the Resource Kit)
REG.EXE (from the Resource Kit / Windows XP)
LDIFDE.EXE (OS Specific)

Either install Cygwin from www.cygwin.com and include the OpenLDAP, dbX.Y: Oracle Berkeley DB (dbX.Y - utilities), and sed packages, or copy the following files from a working Cygwin installation:

  • cygcrypt-0.dll
  • cygcrypto-0.9.8.dll
  • cygdb-4.5.dll
  • cygiconv-2.dll
  • cygintl-3.dll
  • cygintl-8.dll
  • cyglber-2-3-0.dll
  • cygldap-2-3-0.dll
  • cygldap_r-2-3-0.dll
  • cygminires.dll
  • cygsasl2-2.dll
  • cygssl-0.9.8.dll
  • cygwin1.dll
  • db4.5_stat.exe <- only required for DB performance analysis
  • ldapmodify.exe
  • ldapsearch.exe
  • sed.exe
  • slapd.exe
  • sleep.exe
  • uniq.exe

The following directory structure is assumed:

  • \OpenLDAP
    • \ADExport
    • \bin
    • \LDIFs
    • \run
    • \schema

OpenLDAP Schema changes required

The standard LDAP schema supplied with OpenLDAP do not include all the attributes required to import LDIF files from Active Directory.
For this reason, some of the schemas must be edited to include the following attributes:

inetperson.schema

Add:
attributetype ( 1.2.840.113556.1.2.210
        NAME 'proxyAddresses'
        DESC 'rfc822 mail address of group member(s)'
        EQUALITY caseIgnoreIA5Match
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

attributetype ( 1.1.2.1.1 NAME 'department'
        DESC 'Department Name'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE )

attributetype ( 1.1.2.1.2 NAME 'company'
        DESC 'Company Name'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE )
Under:
objectclass     ( 2.16.840.1.113730.3.2.2
Replace the last line of:
MAY (
                audio $ businessCategory $ carLicense $ departmentNumber $
                displayName $ employeeNumber $ employeeType $ givenName $
                homePhone $ homePostalAddress $ initials $ jpegPhoto $
                labeledURI $ mail $ manager $ mobile $ o $ pager $
                photo $ roomNumber $ secretary $ uid $ userCertificate $
                x500uniqueIdentifier $ preferredLanguage $
                userSMIMECertificate $ userPKCS12 )
with
                userSMIMECertificate $ userPKCS12 $ proxyAddresses $ department $ company $ mailNickname)

core.schema

Add:
attributetype ( 0.9.2342.19200300.100.1.43
                NAME ( 'co' 'friendlyCountryName' )
                DESC 'RFC1274: friendly country name'
                EQUALITY caseIgnoreMatch
                SUBSTR caseIgnoreSubstringsMatch
                SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

attributetype ( 0.9.2342.19200300.100.1.4 NAME 'info'
                DESC 'RFC1274: general information'
                EQUALITY caseIgnoreMatch
                SUBSTR caseIgnoreSubstringsMatch
                SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{2048} )

Change line:
objectclass ( 2.5.6.2 NAME ('country' 'co')
to:
objectclass ( 2.5.6.2 NAME ('country')
Under:
objectclass ( 2.5.6.6 NAME 'person'
replace
MUST ( sn $ cn )
with
MUST ( cn )
Replace:
MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
with
MAY ( userPassword $ telephoneNumber $ seeAlso $ description $ sn) )
Under:
objectclass ( 2.5.6.7 NAME 'organizationalPerson'
replace the last line of
MAY ( title $ x121Address $ registeredAddress $ destinationIndicator $
                preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
                telephoneNumber $ internationaliSDNNumber $ 
                facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
                postalAddress $ physicalDeliveryOfficeName $ ou $ st $ l $ c $ country ) )

with
        postalAddress $ physicalDeliveryOfficeName $ ou $ st $ l $ c $ co $ info $ mailNickname) )

Install the OpenLDAP Service

In the \OpenLDAP\bin directory, issue the following commands:
instsrv OpenLDAP-GAL "c:\openldap\bin\srvany.exe"
reg add HKLM\SYSTEM\CurrentControlSet\Services\OpenLDAP-GAL\Parameters /v Application /t REG_SZ /d c:\openldap\bin\slapd.exe
reg add HKLM\SYSTEM\CurrentControlSet\Services\OpenLDAP-GAL\Parameters /v AppParameters /t REG_SZ /d -d0 -f c:\openldap\slapd.conf
reg add HKLM\SYSTEM\CurrentControlSet\Services\OpenLDAP-GAL\Parameters /v Description /t REG_SZ /d LDAP Server for use with Outlook Addressbooks

slapd.conf

The slapd.conf file contains access permissions, the location of the database and the indexes to be created. The minimum configuration required is below:
include         /openldap/schema/core.schema
include         /openldap/schema/cosine.schema
include         /openldap/schema/inetorgperson.schema

pidfile         /openldap/run/slapd.pid
argsfile        /openldap/run/slapd.args

moduleload      back_bdb.la

allow bind_anon_cred

database        hdb
suffix          "dc=XXXX,dc=yyy,dc=zzz"
rootdn          "cn=Manager,dc=XXXX,dc=yyy,dc=zzz"
rootpw          secret
directory       /openldap/ADExport
index           sn      eq
index           cn      eq
index           givenName       eq
index           co      eq
index           description     eq
index           title   eq
index   displayName     eq,sub
index   objectClass     eq 
index   mail    eq,sub

access to * by * read
Note: This allows anonymous ready access to anyone that connects. Also, the indexes could probably be optimized, but it is fast enough for my use.

Import AD entries

The following attributes are needed by Outlook
  • cn
  • displayName
  • description
  • proxyAddresses
  • mail
  • c
  • co
  • l
  • sn
  • st
  • postalCode
  • co
  • department
  • company
  • telephoneNumber
  • homePhone
  • streetAddress <- needs to be changed to postalAddress for Outlook to use it for some reason.
  • givenName
  • physicalDeliveryOfficeName
  • title
  • mobile
  • pager
  • info
  • objectclass
A batch file is created so we can run it as a scheduled task if required. A domain account is required to log in.
Each time an import is done, it is important that there isn’t a build-up of old entries. The easiest way to do this is to delete the OpenLDAP database and create a new one.
The following steps happen:
  1. Stop the service, and pause for a few seconds
  2. Delete the database
  3. Restart the service, and pause for a few seconds
  4. Set up the empty database
  5. Connect to a DC in each domain XXXX and only export objects with email addresses and only the attributes we want
  6. Connect to a DC in each domain XXXX and export the OUs
    Note: Foreign characters will result in base64 encoding, which means that you might have a problem with sed, and will probably have to remove them manually.
  7. Remove the OUs for each entry
  8. Remove the attributes we don’t need (or cause problems)
  9. Import the reformatted entries
Note: All hierarchy (OUs) is removed apart from “DC=XXXX,DC=yyy,DC=zzz” for each entry. This is because LDAP servers do not automatically create the structure when entries are imported and also we don’t need to recreate this for an Outlook Addressbook.

The following is run under C:\OpenLDAP:

  1. net stop openldap-gal
    bin\sleep 5
  2. del \openldap\ADExport\* /q
  3. net start openldap-gal
    bin\sleep 15
  4. bin\ldapmodify -Hldap://localhost -f setupslapd.ldif -D "cn=Manager,dc=XXXX,dc=yyy,dc=zzz" -w secret -x -c
  5. bin\ldifde -b <domainuser> <domain> <password> -s <DC> -f LDIFs\DC.ldif
      -r "(&(|(objectClass=User)(objectClass=contact))(proxyaddresses=smtp:*)(name=*)(!msExchHideFromAddressLists=TRUE))"
      -d "ou=StartingOU,dc=XXXX,dc=yyy,dc=zzz"
      -l cn,displayName,description,proxyAddresses,mail,c,co,l,sn,st,postalCode,co,department,company,
      telephoneNumber,homePhone,streetAddress,givenName,physicalDeliveryOfficeName,title,mobile,pager,info,objectclass
    ...
  6. bin\ldapsearch -LLL -Hldap://<DC> -s sub -x -D "domainuser@XXXX.yyy.zzz" -W -b "OU=StartingOU,DC=XXXX,DC=yyy,DC=zzz"
      "(objectcategory=organizationalunit)" name > OUs.txt <DCLDAPPassword.txt
  7. bin\sed -f OUreformat.sed OUs.txt|sort |bin\uniq > LDIFs\OUsToRemove.sed
    cd LDIFs
    ..\bin\sed -f OUsToRemove.sed DC.ldif >DC2.ldif
  8. ..\bin\sed -f ../AttributesToRemove.sed DC2.ldif >LDAPImport.ldif
  9. ..\bin\ldapmodify -f LDAPImport.ldif -D "cn=Manager,dc=XXX,dc=yyy,dc=zzz" -w secret -x -c > LDAPImport.log 2>&1

setupslapd.ldif contains the following:

dn: dc=XXXX,dc=yyy,DC=zzz
changetype: add
dc: XXXX
objectClass: dcObject
objectClass: organizationalUnit
ou: Outlook Address Book
Of course, the "dn" can be anything you like, but it must match the "dn"s of the LDIFs whatever you are importing. I could have just said "dc=XXXX" and removed "dc=yyy,dc=zzz" from the LDIFs to make things simpler, but at least this means it's the same DN as our AD domain.

OUReformat.sed contains the following:

/^ *$/d
/^dn: /d
/^ /d
/dn:: /d
/name:: /d
/name: _/d
s/name: /,OU=/
s/^/s\//
s/$/,\/,\//
The above removes the continuation lines that we don't need, blank lines reformats the lines into a sed-compatible script file.
You may also want to add your own specific OUs to remove if needed.

AttributesToRemove.sed contains the following:

s/objectClass: user/objectClass: inetOrgPerson/
s/objectClass: contact/objectClass: inetOrgPerson/
s/,OU=Exchange Migration Wizard Created Objects//
s/^streetAddress:/postalAddress:/
The above removes the objectclasses that confuse things, and renames streetAddress to postalAddress or Outlook won't show the address. Note: doing this means that Thunderbird won't show the address (maybe Thunderbird does like the streetAddress attribute, but I haven't had time to try this).

TBC...
chris.clemson@ihg.com

You may also need to add the following to <B>core.schema</B>:

<PRE>
attributetype ( 1.2.840.113556.1.2.447 NAME 'mailNickname'
        DESC 'MS Exchange alias'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
</PRE>
chris.clemson@ihg.com
[Append to This Answer]
Previous: (Answer) Is an export license required to export OpenLDAP Software? What ECCN has been given to OpenLDAP Software?
Next: (Answer) OpenLDAP Mirror Mode
This document is: http://www.openldap.org/faq/index.cgi?file=1461
[Search] [Appearance]
This is a Faq-O-Matic 2.721.test.
© Copyright 1998-2013, OpenLDAP Foundation, info@OpenLDAP.org