LDAP System Administration
Page 12
root@master# slapcat -b "dc=plainjoe,dc=org" -l contents.ldif
...copy contents.ldif to the slave server...
root@replica1# slapadd -l contents.ldif
In this example, specifying the base suffix with the -b option is not necessary because your server contains only one partition. Had there been more than one database section in slapd.conf, the base suffix would have specified which partition to dump. Specifying a base suffix isn't necessary when you import the file into the replica because slapadd parses the configuration file and places the data into the first database to match the base suffix of the LDIF entries.
Once the data has been copied to the slave server, it is time to update the replica's slapd.conf to accept updates from the master server. The global section of the replica's configuration file will be identical to the master server's. However, certain pieces of information, such as the server's public certificate, should be unique to the slave. The database section of the slave's slapd.conf will also be identical, minus the replication parameters and with an appropriate local rootdn and rootpw. For the purposes of this chapter, the slave's database section contains the following rootdn and rootpw:
## -- slave slapd --
## replica's administrative DN
rootdn "cn=replica,dc=plainjoe,dc=org"
## Salted Secure Hash version of MyPass
rootpw {SSHA}SMKnFPO435G+QstIzNGb4RGjT0KLz2TV
To make the server act as a slave, you must add two parameters to the configuration. Just as the master must know where to send updates, the slave server must know who is authorized to make these changes. This is done by defining an updatedn :
## -- slave slapd --
## Define the DN that will be used by the master slurpd to replicate data. Normally,
## this is the rootdn of the slave server or, at the minimum, a DN that is allowed
## write access to all entries via an ACL.
updatedn "cn=replica,dc=plainjoe,dc=org"
Because a slave server contains only replicated data and OpenLDAP currently supports only a single master replication system (i.e., updates must be made on the master directory server), the slave server requires an LDAP URL (updateref) that points clients to the master directory server. The slave refers clients to the master when clients send modification requests. Here's the appropriate addition to the database section of the replica's slapd.conf:
## -- slave slapd --
## Specify the LDAP URL of the master server, which can accept update requests.
updateref ldap://pogo.plainjoe.org
* * *
Tip
Development versions of OpenLDAP support an experimental implementation of a multimaster replication protocol. Multimaster replication means that changes to the directory can be accepted at any replica: the replica propagates the changes to all servers containing copies of the partition. Multimaster replication is not covered in this book.
* * *
This completes step 4 of the configuration process. Steps 5 and 6 are to launch the master and slave's slapd processes using the procedure described in earlier chapters.
slurpd's replogfile
As Figure 5-1 illustrates, the slurpd daemon processes the change log written by slapd. The replication log uses a format similar to the LDIF examples used throughout this book. After reading the replogfile , slurpd copies the entry to its own replay log. The location of the slurpd.replog file can be controlled using the -t command-line option when starting slurpd. In a default installation, slurpd.replog will be stored in /usr/local/var/openldap-slurp/replica/.
The following log entry in the replogfile was generated when the email address for cn=Jerry Carter,ou=people,dc=plainjoe,dc=org was changed to jcarter@nowhere.com:
replica: pogo.plainjoe.org
time: 975434259
dn: cn=jerry carter,ou=People,dc=plainjoe,dc=org
changetype: modify
replace: mail
mail: jcarter@nowhere.com
-
replace: entryCSN
entryCSN: 2002110403:55:49Z#0x0001#0#0000
-
replace: modifiersName
modifiersName: cn=Manager,dc=plainjoe,dc=org
-
replace: modifyTimestamp
modifyTimestamp: 20001128175739Z
-
While only one attribute value was changed, the replication log entry updates four attributes: mail (as expected), plus modifiersName , modifyTimestamp , and entryCSN . These last three attributes, two of which are described in RFC 2251, are maintained by the LDAP server and cannot be modified by clients.
The log entry also specifies two additional values not used in normal LDIF entries. The replica directive defines the host to which the change should be propagated. There can be multiple replica lines if a partition will be synchronized to several directory slaves. The time parameter defines the timestamp of the entry in seconds since 1970 GMT. slurpd maintains the timestamp of the most recently read change, which prevents it from reparsing entries it has already processed. This state information is stored in a status file named slurpd.status in the same directory as the slurpd.replog file.
slurpd reads entries in the replication log file one at a time and propagates the changes using basic LDAP commands (e.g., add, modify, delete, modrdn, etc.). If a change cannot be made, slurpd writes the entry and reason for the failure to a reject log named
Certain errors, such as a network problem in the connection from the server to the slave, cause slurpd to requeue a modification. However, any entry written to the reject log cannot be replicated in its current state. These entries will require manual intervention on a case-by-case basis. If the update resulted in an object schema violation, perhaps one of the schema files was left out of the configuration file. If the replica arrived in a state inconsistent with the directory master, attempting to add an entry that already existed would also result in an error. These types of circumstances can be very data-specific, and the examples given here represent only a few of the possible causes. In any case, the appropriate response to an error isn't to try to update the slave by hand; rather, you should figure out why the update can't take place automatically, and fix the appropriate configuration file.
Our setup will utilize slurpd as a daemon that monitors the replication log file and propagates changes periodically. However, it can also operate as a command-line tool to process a single change log and exit. This is referred to as "one shot" mode, and it's invaluable for dealing with rejected entries. A complete list of command-line options used when starting slurpd is given in Table 5-1.
Table 5-1. Command-line options for slurpd
Option
Description
-d integer
Specifies the debugging information to be written to the log. See the discussion of the loglevel slapd.conf parameter for more information on the debugging flags.
-f "config filename"
Specifies the location and filename of the slapd.conf file to be used.
-r replogfile
Specifies the location and filename of the replication log to be processed. The -r switch is often used in conjunction with the slurpd's one-shot mode to process a particular file.
-o
Executes slurpd in one-shot mode to process a single replication log and exit.
-t directory
Specifies the directory to be used for temporary files such as lock and status files. The default is to store the files in /usr/local/var/openldap-slurp/replica/.
-k "srvtab file"
Specifies the location of the srvtab file when using LDAPv2 Kerberos 4 binds to a slave slapd server.
&
nbsp; To complete the configuration of your directory replica, you must start the slurpd daemon on the master server. To do so, execute slurpd as root from a shell prompt:
root@master# /usr/local/libexec/slurpd
From this point on, any changes made to the master directory will be replicated to the slave server. In current 2.x versions, the slurpd thread responsible for monitoring the replication log checks every three seconds for updates and propagates these updates as necessary. This interval is not configurable from the command line nor from slapd.conf. However, if less frequent updates are required, slurpd could be run manually using the -o argument to process the replication log when desired.
* * *
Using a Replica in a Backup Plan
Backing up a directory that must be available 24 hours a day can require special arrangements. By using replication, a slave server can act as a backup server.
Even if the backup plan relies on offline storage, a directory replica can be very helpful. If you stop the slurpd daemon on the master server, the replica server contains a read-only copy of the directory at that point in time. Of course, the master slapd continues to write changes to the replogfile. You can now use slapcat on the slave to dump the database files to LDIF while slapd is running because data is guaranteed not to change in mid-backup. Once the backup is complete, restarting slurpd ensures that all changes made to the master while the replica was being backed up will be propagated, bringing the slave in sync with the current state of the directory.
* * *
Distributing the Directory
The scenarios presented thus far have all assumed that the entire directory consists of a single partition on one server. In the real world, this may not always suffice. There are many reasons (which I touched on in Chapter 2) for splitting a directory into two or more partitions, which may reside on multiple servers.
Let's assume that, according to Figure 5-2, the top level of your directory server (dc=plainjoe,dc=org) is maintained by one department, and the server containing host information (ou=hosts,dc=plainjoe,dc=org) is managed by another. How can these two directories be combined into one logical DIT?
Figure 5-2. Two separate directory partitions held by different servers
The definition for the ou=hosts partition held by the second server is very similar to the database section we have been using so far. The main changes are to the suffix served by the backend (ou=hosts,dc=plainjoe,dc=org) and the directory in which the BerkeleyDB files are stored (/var/ldap/hosts/). The rootdn (cn=Manager,ou=hosts,dc=plainjoe,dc=org) must also be updated due to the requirement that it must exist within the partition's naming context.
#######################################################
## Partition on second server holding ou=hosts
database bdb
## Define the root suffix you serve.
suffix "ou=hosts,dc=plainjoe,dc=org"
## Define a root DN for superuser privileges.
rootdn "cn=Manager,ou=hosts,dc=plainjoe,dc=org"
## Define the password used with rootdn. This is the Base64-encoded MD5 hash of
## "secret."
rootpw {SSHA}2aksIaicAvwc+DhCrXUFlhgWsbBJPLxy
## Directory containing the database files
directory /var/ldap/hosts
## Files should be created rw for the owner **only**.
mode 0600
## Indexes to maintain
index objectClass eq
index cn pres,eq
## db tuning parameters; cache 2,000 entries in memory
cachesize 2000
# Simple ACL granting read access to the world
access to *
by * read
Chapter 2 described a distributed directory implemented by superior knowledge references (referrals) that point from the root of a subtree to the server of the larger directory, and subordinate knowledge references (references) that point from a node in the larger directory to the subtree, or partition, to which it should be attached. In terms of Figure 5-2, these knowledge references would link the dc=plainjoe,dc=org partition to ou=hosts,dc=plainjoe,dc=org, as shown in Figure 5-3.
Figure 5-3. Connecting the two partitions using a referral and a reference
These connecting links allow a client to request a search that starts at any node in the directory and continues down through the directory tree, traversing all the directory's partitions. In this case, the search reference URI is returned to the client, which then has the option of continuing the search using the new server and the new base suffix.
The slapd.conf for the server holding the ou=hosts tree possesses a global section identical to your existing server, with one exception. OpenLDAP uses the referral global parameter to define an LDAP URI for the server's superior knowledge reference. This feature is implemented as a global, server-wide parameter as opposed to a database-specific directive because a superior knowledge reference refers the client to a server that has knowledge that the server receiving the request does not possess. Normally, this superior server would be higher in the directory tree, but OpenLDAP does not enforce this rule. If the ou=hosts partition is held by a server separate from one containing the top-level naming context, the referral parameter would look similar to the following:
## slapd.conf for ou=hosts (ldap2.plainjoe.org)
##
##
## . . .
## Define the URL (only host:port) for the host that clients should contact in the
## event that you cannot service their requests.
referral ldap://master.plainjoe.org:389/
Subordinate knowledge references are implemented as entries within the directory itself. These entries use the referral structural object class defined in RFC 3296. This class contains a single required attribute named ref, which holds the LDAP URI for the root of the subtree. So to connect the top-level partition in Figure 5-3 to the people organizational unit, you must create the referral entry to the directory. Assuming that the ou=hosts naming context is held by a server named ldap2.plainjoe.org, this ldapadd example reads the new entry from standard input:
$ ldapadd -H ldap://localhost/ -D "cn=Manager,dc=plainjoe,dc=org"
> -w secret -x << EOR
> dn: ou=hosts,dc=plainjoe,dc=org
> ou: people
> objectClass: extensibleObject
> objectClass: referral
> ref: ldap://ldap2.plainjoe.org/ou=hosts,dc=plainjoe,dc=org
> EOR
adding new entry "ou=hosts,dc=plainjoe,dc=org"
* * *
Warning
The OpenLDAP server implements the ManagerDSAIT LDAP control defined in the RFC 3088. This control enables a client to access the actual attribute values (including the ref attribute) in a referral entry without having the server return the referral itself. If a need arises to update a referral entry, enable this control by using the -M (or -MM) command-line option to ldapmodify.
* * *
Next, create a sample in the ou=hosts tree ldap2.plainjoe.org for later use:
$ ldapadd -H ldap://ldap2.plainjoe.org/
> -D "cn=Manager,ou=hosts,dc=plainjoe,dc=org"
> -w secret -x << EOR
> dn: ou=hosts,dc=plainjoe,dc=org
> objectclass: organizationalUnit
> ou: hosts
> description: Container for host information in plainjoe.org domain
> EOR
adding new entry "ou=hosts,dc=plainjoe,dc=org"
The next section will show you how to handle these search references when querying the directory using ldapsearch.
Advanced Searching Options
Chapter 4 presented LDAP searches as a means of verifying the correctness of your directory. That's obviously a very limited use of the search capability: a directory isn't much use if you can't search it. Given our limited goals in the previous chapter, we didn't do justice to the topic of search filters. It's now time to take a more t
horough look at the topic of filters.[1]
In its commonly used form, an LDAP search filter has the following syntax:
( attribute
filterOperator
value )
The attribute is the actual name of the attribute type. The filterOperator is one of:
=
For equality matches
~=
For approximate matches
<=
For less than comparisons
>=
For greater than comparisons
If you deal only with string comparisons, you may only need the equality operator.
The value portion can be either an absolute value, such as carter or 555-1234, or a pattern using the asterisk (*) character as a wildcard. Here are some wildcard searches:
(cn=*carter)
Finds all entries whose cn attribute ends in "carter" (not just those with a last name of Carter)
(telephoneNumber=555*)
Finds all telephone numbers beginning with 555
You can combine single filters like these using the following Boolean operators:
&
Logical AND
|
Logical OR
!
Logical NOT
LDAP search filters use prefix notation for joining search conditions. Therefore, to search for users with a surname (sn) of "smith" or "jones," you can build the following filter:
(|(sn=smith)(sn=jones))
The sn attribute uses a case-insensitive matching rule, so it doesn't matter whether you use "Smith," "smith," or "SMITH" in the filter (or in the directory itself). To look for people with a last name of "smith" or "jones" and a first name beginning with "John," the search would be modified to look like: