LDAP

What Is LDAP?
LDAP is a little bit confusing to wrap your head around, at first, so before I start throwing terms around, allow me to outline what it is.

LDAP is a protocol for distributing a provides a::hierarchical database. It is not a database, itself; it isn't even a program at all. It's a is a::protocol, similar to HTTP or DNS. There are different implementations of LDAP. We use OpenLDAP. This is a program, or rather a collection of programs. Microsoft's Active Directory is essentially LDAP and a bunch of other crap to use LDAP. Netscape had another implementation, which is now Red Hat Directory Server, and open source.

LDAP itself is not a database; neither are most of the implementations. Active Directory, I'm sure, includes a database in the complete package. OpenLDAP does not. Instead, you must provide a requires::database backend. Usually, bdb (Berkley Database) or ldbm (GNU's version of DBM, an age-old database) are used. These are really simple, basic databases, without all the fancy features of a MySQL or PostGreSQL. You can use a more elaborate database if you want, but there's not really any point or benefit. These mini-databases are optimized for simple key-data pairs, which is what LDAP needs. The elaborate databases might actually slow things down.

Command-Line Tools
The server itself:
 * slapd

The ldap* tools are for modifying the data in a running ldap server:


 * ldapadd
 * ldapdelete
 * ldapmodify
 * ldappasswd
 * ldapsearch

The slap* tools are for viewing and modifying the data in a ldap database when the server is not running:


 * slapadd
 * slapcat
 * slapindex
 * slappasswd

The former ldap tools are the ones you should be using, unless you're trying to repair a broken system. The slap tools are dangerous.

The fudo* tools are intended for manipulating our database:


 * Fudo User Management Tools

LDIF Files
LDIF files are the most common way to insert new entries into an LDAP database. Since LDAP is a read-optimized protocol, and not optimized for writes, it requires that writes happen in the form of records, not fields. You cannot ‘open’ a record, and then proceed to modify it field by field, as in MySQL. This is equivalent to a database in which you can only work with whole rows, not single fields. In fact, even when you modify a record using a tool like ldapmodify, what happens internally is the old record is removed, and a new, modified one is added.

The usual way to modify a database, then, is to create an LDIF file containing either a new record, or instructions on how to modify a record. It would look something like this:

dn: cn=irc,ou=groups,dc=fudo,dc=org objectClass: posixGroup cn: irc gidNumber: 39 memberUid: niten memberUid: r3d3 memberUid: reaper

A brief analysis:


 * ldap:dn - Distinguished Name, a name which is unique to this particular record
 * ldap:objectClass - LDAP is object-oriented, in that each record has a 'class', which determines what other properties it has. For example, 'posixGroup' object records can have any number of 'memberUid' properties.
 * ldap:cn - Common Name, the short name for this element. Note that it matches the first part of the ldap:dn.  If the distinguished name of the element was "uid=reaper,ou=members,dc=fudo,dc=org", then rather than "cn: irc" we would have "uid: reaper" here.
 * ldap:gidNumber and ldap:memberUid - Both properties which come from the ldap:posixGroup ldap:objectClass.

An LDIF file can contain any number of records, separated by a blank line. They can be used to add records to the database using either slapadd (if the server is not running) or ldapadd (if it is), and are used by ldapmodify for modifying existing records.

For further information on LDIF files see: LDIF Files.

LDAP Naming and Hierarchy
LDAP databases are hierarchical, starting from a root and branching out. This used to be a common way to organize databases before relational databases appeared, but it's fallen out of favour because it's usually ridiculous, and most modern databases are relational. Another example of a hierarchical database is DNS, which also shares with LDAP it's distributed nature.

Top of the Hierarchy
Originally, back in the mid-80s when LDAP was first RFC'ed, the recommended root of your hierarchy was your physical location, encoded like so: "org=fudo,city=winnipeg,province=manitoba,country=canada". Everything else would go 'below' that, so "uid=reaper,ou=members,org=fudo,city=winnipeg,province=manitoba,country=canada". There are some obvious problems with that--organizations can and do exist in many places, and they move around. Later on, the favoured way to start your hierarchy was by domain name. This is the method Fudo uses. The top of the Fudo tree is "dc=fudo,dc=org" where ldap:dc stands for Domain Component. Note that this is totally arbitrary. Don't get confused and wonder where the subdomains are or anything. It doesn't map to the domain name in any real way. You could really start your tree anywhere you wanted, as long as it was unique.

The Meta-Tree
The reason the top of an LDAP tree must be unique is that every LDAP tree in the world is, in theory, part of a super-meta-tree. Each organization in that tree has a particular number, the OID (for Fudo.org this is oid number:=1.3.6.1.4.1.17637). The tree doesn’t only contain organizations, though; it contains everything, including variable types (’integer’ and ‘character’, ‘string’, ‘address’, ‘phoneNumber’, ‘unixAccount’ and ‘fudoAccount’ could all be found somewhere on the tree) and all kinds of other crap as well. In fact, I'm pretty sure SNMP uses this self-same tree to define devices and properties of devices. This makes it very difficult to wrap your head around, and especially expand. Luckily, it's mostly possible to forget about the larger world when you're working with your own LDAP database.

LDAP Naming Scheme and Distinguished Names
Every record in an LDAP database has a Distinguished Name, which, as the name suggests, is distinguishing--that is, unique in the database. The naming scheme takes a while to get used to, but there's a reason it's so bizarre. Whereas DNS would render a domain as "fudo.org", LDAP would use "dc=fudo,dc=org" (where dc is the Domain Component objectClass). Everything else falls below that domain in the hierarchy, which means that it comes before the domain in the distinguished name.

The user 'niten' is located at "uid=niten,ou=members,dc=fudo,dc=org". That record contains information about the user 'niten'--name, password, Unix shell and home directory. Each of the sections of the dn has a meaning. uid is a property of posixAccount objects, and acts as a key, in that it is unique in that part of the tree (i.e. it distinguishes this particular record). ou is short for Organizational Unit, and is a generic object type which is used to simply divide a tree into parts; examples are "ou=groups" or "ou=members".

A host would be stored at "cn=athens,ou=hosts,dc=fudo,dc=org". cn is used as a generic name, when simple names will do, and are used for hostnames, groupnames, and others. In fact, it would be perfectly legitimate for a user to be located at "cn=Peter Selby,ou=members,dc=fudo,dc=org" (though that name would have to be unique). This is only very slightly different from the example given above--the record is actually stored in the same spot. For the sake of consistency, though, it's best to stick with one key in each section, and uid seems like a better choice than common name, since it's more likely to be unique.