I have gone through so many LDAP address book howtos that have not worked despite following them step for step, after finally getting it up and running I figured I’d write my own.

Firstly, this is based on a Debian or Ubuntu system, other systems may have different file locations and default config file contents so I can’t guaranty a flawless install if you follow these steps using another system. I did this under Debian Lenny and using slapd 2.4.11 (OpenLDAP) and Thunderbird 3.0.

Secondly this is a very basic setup, there is no security, no user or group setup, no encryption. If you set this server up, anyone with access to the server has access to your address book. This is meant to be a very simple guide to hopefully get people started. USE AT YOUR OWN RISK. Hopefully I’ll get to writing a more secure howto later.

The howto follows the same procedures to the one found here but doesn’t go into the extra details regarding security.

This howto uses the Linux command line and Debian package manager (apt), if your not comforatble using these please learn first.

Lets get start started, firstly we’ll install slapd and while we’re are at it we’ll install the ldap-utils package. I wont be using it in this guide but you may come across other titbits in your LDAP travels that make use of some of the contained tools.

sudo apt-get install slapd ldap-utils

Once they are installed, lets generate a password hash to use for the LDAP admin user

slappasswd

After typing and confirming your password, a hash should be returned, ie.

{SSHA}uXQ01mph2bMe2HkQhvUNqrR1LNqvixUa

record it, we’ll use this later.

Thunderbird uses its own LDAP schema and everything I’ve read indicates that the schema is still in flux. This Mozilla wiki page seems to have the latest schema for version 1.5 of Thunderbird and above. How ever copying the code from this page gives you an annoying whitespace at the start of each line, annoying because OpenLDAP will throw an error trying to read it. I’ve replicated the schema as of 24th December 2009 (yes I’m writing this Christmas eve) below. You need to save this text in the file /etc/ldap/schema/mozillaAbPersonAlpha.schema. You need to have root access to do this so don’t forget to sudo with your favourite editor :-)

sudo vi /etc/ldap/schema/mozillaAbPersonAlpha.schema
OR
sudo nano /etc/ldap/schema/mozillaAbPersonAlpha.schema

Here’s the schema text to place in the file

# Mozilla: @VERSION@
#
# mozillaAbPersonAlpha
#
# Created initial version --[[User:Standard8|Standard8]] 12:21, 5 Dec 2005 (PST)
# Change fax to facsimileTelephoneNumber to reflect core.schema
# ({{bug|327872}} --[[User:Standard8|Standard8]] 12:45, 11 Dec 2008 (PST)
#
# This file contains LDAPv3 schema for use with the Mozilla Address Book
# and is intended to ...

# Depends upon
#   Definition of an X.500 Attribute Type and an Object Class to Hold
#   Uniform Resource Identifiers (URIs) [RFC2079], and A Summary of
#   the X.500(96) User Schema for use with LDAPv3 [RFC2256] (core.schema)
#
#   The COSINE and Internet X.500 Schema [RFC1274] (cosine.schema)
#
#   The InetOrgPerson Schema [RFC2798] (inetorgperson.schema)

# 1.3.6.1.4.1.13769.4.x - Mozilla AB 'Other' tab

attributetype ( 1.3.6.1.4.1.13769.4.1 NAME 'mozillaCustom1'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.13769.4.2 NAME 'mozillaCustom2'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.13769.4.3 NAME 'mozillaCustom3'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.13769.4.4 NAME 'mozillaCustom4'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )

# 1.3.6.1.4.1.13769.3.x - Mozilla AB 'Address' tab

attributetype ( 1.3.6.1.4.1.13769.3.1 NAME 'mozillaHomeStreet'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.13769.3.2 NAME 'mozillaHomeStreet2'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.13769.3.3 NAME 'mozillaHomeLocalityName'
         SUP name SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.13769.3.4 NAME 'mozillaHomeState'
         SUP name SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.13769.3.5 NAME 'mozillaHomePostalCode'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.13769.3.6 NAME 'mozillaHomeCountryName'
         SUP name SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.13769.3.7 NAME 'mozillaHomeUrl'
         EQUALITY caseIgnoreMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.13769.3.8 NAME 'mozillaWorkStreet2'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.13769.3.9 NAME 'mozillaWorkUrl'
         EQUALITY caseIgnoreMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )

# 1.3.6.1.4.1.13769.2.x - Mozilla AB 'Contact' tab

attributetype ( 1.3.6.1.4.1.13769.2.1
         NAME ( 'mozillaNickname' 'xmozillanickname' )
         SUP name )

attributetype ( 1.3.6.1.4.1.13769.2.2
         NAME ( 'mozillaSecondEmail' 'xmozillasecondemail' )
         EQUALITY caseIgnoreIA5Match
         SUBSTR caseIgnoreIA5SubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.13769.2.3
         NAME ( 'mozillaUseHtmlMail' 'xmozillausehtmlmail' )
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )

# AOL Instant Messenger (AIM) Identity
attributetype ( 1.3.6.1.4.1.13769.2.4
         NAME ( 'nsAIMid' 'nscpaimscreenname' )
         EQUALITY telephoneNumberMatch
         SUBSTR telephoneNumberSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )

# 1.3.6.1.4.1.13769.9 - Mozilla AB objectclasses

# The mozillaAddressBookEntry object class is used to define entries
# representing Cards in the Mozilla Address Book.  The commonName attribute
# is used for naming entries of this object class, but may not be unique.
#             department $

objectclass ( 1.3.6.1.4.1.13769.9.1 NAME 'mozillaAbPersonAlpha'
         SUP top AUXILIARY
         MUST ( cn )
         MAY( c $
              description $
              displayName $
              facsimileTelephoneNumber $
              givenName $
              homePhone $
              l $
              mail $
              mobile $
              mozillaCustom1 $
              mozillaCustom2 $
              mozillaCustom3 $
              mozillaCustom4 $
              mozillaHomeCountryName $
              mozillaHomeLocalityName $
              mozillaHomePostalCode $
              mozillaHomeState $
              mozillaHomeStreet $
              mozillaHomeStreet2 $
              mozillaHomeUrl $
              mozillaNickname $
              mozillaSecondEmail $
              mozillaUseHtmlMail $
              mozillaWorkStreet2 $
              mozillaWorkUrl $
              nsAIMid $
              o $
              ou $
              pager $
              postalCode $
              postOfficeBox $
              sn $
              st $
              street $
              telephoneNumber $
              title ) )

Now that we’ve got the schema ready, lets configure the LDAP daemon (in our case slapd). I use vi so from now on whenever we need to edit something I’ll just show the vi command.

sudo vi /etc/ldap/slapd.conf

First thing we need to do is tell slapd about our Mozilla schema and also comment out the line “include         /etc/ldap/schema/nis.schema”. Look for the schema includes at the top of the file and you should finish up with something like the following:

# Schema and objectClass definitions
include         /etc/ldap/schema/core.schema
include         /etc/ldap/schema/cosine.schema
#include         /etc/ldap/schema/nis.schema
include         /etc/ldap/schema/inetorgperson.schema
include         /etc/ldap/schema/mozillaAbPersonAlpha.schema

Next we’ll set the base suffix for our database, you can make this unique by using your network domain (ie example.homedns.org). Look for the suffix entry for database #1.

# The base of your directory in database #1
suffix          "dc=example,dc=homedns,dc=org"

The next entry down should be the rootdn, this specifies the database superuser, we’ll use the common name (cn) of admin, but you can choose anything you want. Don’t forget to use your own base suffix that you set in the previous step.

rootdn          "cn=admin,dc=example,dc=homedns,dc=org"

You’ll need to add a rootpw entry (the superuser password), remember that hash that we recorded earlier, use it now.

rootpw          {SSHA}uXQ01mph2bMe2HkQhvUNqrR1LNqvixUa

Now its quite likely your going to want to search your address book and may run into trouble if your database fields aren’t indexed. We’ll add a new index specification in the database #1 section.

index           sn,givenName,cn,mail eq,sub

This makes sure that the fields Thunderbird uses to search are indexed.

Since we’ve commented out the nis.schema file we’ll need to make some changes to one of the access files, search for the line

access to attrs=userPassword,shadowLastChange

and change it to:

access to attrs=userPassword

Now you can save and exit the editor.

Restart the server to load in the new configuration.

sudo /etc/init.d/slapd restart

Any errors here means you should go back and check the edits you’ve just made to the configuration file. You can also check the syslog file at /var/log/syslog for error messages.

Now we can start setting up the actual database, firstly clean out any existing data (Yes we are erasing any existing data, if you don’t want to lose anything don’t do this but suffer any consequences/confusion in silence)

sudo rm -rf /var/lib/ldap/*

and now we’ll put together an initialisation file.

vi ab_init.ldif

Firstly add this to setup our top level

dn: dc=example,dc=homedns,dc=org
objectClass: top
objectClass: dcObject
objectClass: organizationalUnit
dc: example
ou: LDAP Server

Next we’ll add the address book level

dn: ou=Addressbook,dc=example,dc=homedns,dc=org
objectClass: top
objectClass: organizationalUnit
ou: Addressbook
description: LDAP Addressbook

Make sure you replace “dc=example,dc=homedns,dc=org” with your own suffix specified earlier

Save and exit.

The above file will create our address book database structure, lets create an entry to go into that structure.

vi ab_entry.ldif

populate the file with:

dn: cn=Worker Drone+mail=worker@theman.com,ou=Addressbook,dc=example,dc=homedns,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
objectclass: mozillaAbPersonAlpha
givenName: Worker
sn: Drone
cn: Work Drone
mail: worker@theman.com
mozillaSecondEmail: player@thebeach.com
mozillaNickname: player
#modifytimestamp: OZ
homePhone: 5555555
telephoneNumber: 6666666
pager: 4567890
fax: 7777777
mobile: 8888888
mozillaHomeStreet: 1 The Home Street
mozillaHomeLocalityName: HomeTown
mozillaHomeState: Home State
mozillaHomePostalCode: 9999
mozillaHomeCountryName: Homeland
street: 1 The Work Road
l: WorkTown
st: Work State
postalCode: 8888
c: Workland
title: Worker
o: The Man

Remember to use your own suffix in place of  “dc=example,dc=homedns,dc=org”. Using these two files we can build and populate our database. We do this using the slapadd command and because the slapadd command will create files with ownership of the user that runs the command we need to make sure that we either run the command as the same user that will run the slapd deamon or make sure we adjust the permissions after. Lets run slapadd as “openldap” the Debian slapd user

sudo -u openldap slapadd -v -l ab_init.ldif

and

sudo -u openldap slapadd -v -l ab_entry.ldif

assuming all went well we can restart the daemon to load in this new data

sudo /etc/init.d/slapd restart

We now have an LDAP database that is ready to be accessed using the Thunderbird address book.

Open your address book in Thunderbird and select File -> New -> LDAP Directory. On the general tab of the Directory Server properties popup use the “Name:” field to give your address book a name, the “Hostname.” is the address (DNS or IP) to your LDAP server,the “Base DN.” is the address book DN that we specified in the init file, in this case “ou=AddressBook,dc=example,dc=homedns,dc=org”.  The port should be left at the default 389 and leave the Bind DN blank. The image below should give you an idea.

That’s pretty much it, you should have a new address book in your Address Books list, select it and try searching for the entry we created (try searching for ‘@’). LDAP address books will not display all their entries, they will only provide search results. If you can’t get any search results check all of the steps, restart Thunderbird and check for errors in /var/log/syslog.