For part 3 of this tutorial, which covers the client side configuration for OpenLDAP, click here.

The Data

At this point, we’ve planned our directory, installed and configured the server, and configured the client. We’ve tested that the client can communicate with the server. Now we need to put some data in our directory. To do that, we’re going to use the LDAP Data Interchange Format, or LDIF, to create records to insert. I’ll cover the two main ways to add records to the directory, and I’ll also show you how to use scripts provided with OpenLDAP to convert your existing users.

LDIF

This first thing you need to know to insert records into your directory is the LDAP Data Interchange Format, or LDIF, file format. It looks complicated at first, but it’s really quite simple. There are a couple of requirements to all LDIF records for them to be accepted by the LDAP server. First, an LDIF record always needs a DN statement. Recall from previous steps of this guide that the DN is the distinguished name of a record that is used to uniquely identify it within the directory. It’s essentially like the primary key of a database, so naturally your record will need one. As with all other steps of the guide, the DN is comprised of the unique identifier of the record within its directory as well as the “path” of the directory up to the root. So, your record will possibly begin by looking like this:

dn: cn=testuser,ou=people,dc=example,dc=com

As you can see, the line is in the format “field: value”. All LDIF records follow this format. You should put only one field on each line because there is no special field separator. There should also be at least one blank line in between records if you have more that one in your file.

The second requirement in your record is an objectClass identifier. As also previously stated, every record in an LDAP directory must have at least one objectClass associated with it. This provides the record with the required structure that it must follow. Your record can have many objectClass fields in it, however, and you can define them all in LDIF.

objectClass: top
objectClass: posixAccount
objectClass: account

Once again, you see one field per line in the same format as the DN. These objectClass fields determine what the third requirement in your LDIF record is. Each objectClass specifies certain attributes that are required. You must insert lines for each of these attributes or the LDAP server will reject your record. For instance, posixAccount must have values set for cn, uid, uidNumber, gidNumber, and homeDirectory. If any of these fields is omitted, the record will cause an error when using ldapadd.

Initial LDAP Records

Now that you know the format of an LDIF record, we need to create the records that will be required to get your directory up and running. Before you even get a chance to add any user accounts or other information you wish to store, you have to create the directory structure to put them in. Your directory starts out completely empty, without even the root present. So, that’s where we should start. Lets create a record for the root of your new directory.

dn: dc=example,dc=com
dc: example
o: example.com
description: Root LDAP entry for example.com
objectClass: top
objectClass: dcObject
objectClass: organization

This record defines the root of the LDAP directory for example.com. The DN is just the root DN. The required attributes dc and o are filled in. After this is added, we will have a root directory to work within.

Next, we need to create the subdirectories we plan to put users, groups, hosts, and more in.

dn: ou=People,dc=example,dc=com
ou: People
description: All people in example.com
objectClass: organizationalUnit

dn: ou=Groups,dc=example,dc=com
ou: Groups
description: All groups in example.com
objectClass: organizationalUnit

dn: ou=Hosts,dc=example,dc=com
ou: Hosts
description: All hosts in example.com
objectClass: organizationalUnit

This will create the three subdirectories mentioned above. The root directory was an objectClass organization, and each of these are organizationalUnits. Also note that you can combine all of the records so far into one file to add at once.

Inserting Records

There are two ways to insert records into your LDAP directory. If you are on the server itself, you can use a binary called slapadd. This is the server-side add utility, and it requires that the server be shut off to use it. It cannot add records to a running LDAP server. The other utility, ldapadd, can be used from any machine configured to use that LDAP server. This client-side binary does not require the server to be shut down, but it is also meant for smaller additions than slapadd. The general rule of thumb is to use slapadd when you’re setting your directory up for the first time because that will normally be your largest insert. It’s also a time when you can afford to have the server shut down since nobody can use it yet. I will show you how to use both utilities here.

Using slapadd

The basic syntax of slapadd is fairly simple. You can use the man command or a Google search to look through all the options, but the most important and useful ones are:

-v: verbose mode
-c: continuation mode
-u: dry run mode
-l: LDIF file to use

The only required option of the ones above is -l. Obviously, if you’re using an LDIF file to add records to a database, you need to tell it which file to use. The others are very useful for debugging your file though. Verbose mode is fairly obvious. You get more information than normal so you can hopefully see more about things going wrong, if anything. Continuation mode prevents the utility from terminating when it reaches its first error. Normally, slapadd will stop processing a file after just a single error. Well, if you’re just testing the file, you might want it to continue regardless so you can see all errors in a file. This is typically used in conjunction with the dry run mode, which just tells you if a record would be added successfully or not. If you have a file with many records, these two options are indispensable for quickly debugging any issues.

So, lets assume we put all our records above into a file called ldap.ldif. To test this file, you would want to run this:

slapadd -vcul ldap.ldif

This would generate the following if everything is correct:

added: "dc=example,dc=com"
added: "ou=People,dc=example,dc=com"
added: "ou=Groups,dc=example,dc=com"
added: "ou=Hosts,dc=example,dc=com"

It didn’t actually add anything yet, but you can see that every record is fine. Now, lets assume that I had forgotten the organization name in the root DN entry. If I run slapadd, I get this:

Entry (dc=example,dc=com): object class 'organization' requires attribute 'o'
slapadd: dn="dc=example,dc=com" (line=7): (65) object class 'organization' requires attribute 'o'
added: "ou=People,dc=example,dc=com"
added: "ou=Groups,dc=example,dc=com"
added: "ou=Hosts,dc=example,dc=com"

It tells me exactly what’s missing in which record. So debugging is fairly straight forward most of the time. Now if you remove the c and u options, you can actually add those records to the directory. You now have all the structure in place to be able to add users, groups, and more.

There is one last step that you must complete before restarting the directory, though. For the sake of argument, lets say you were running slapadd as root. If you add a number of records, there will be a number of new files added to the directory. These files will all be owned by root, but LDAP requires that they be owned by the ldap user. So, as root, run:

chown -R ldap:ldap /var/lib/ldap

Now you can start the ldap service again with all your new records in place. Note that this step has to be done every time you run slapadd before starting LDAP again.

Using ldapadd

The other method for adding records is with ldapadd. There are a few additional options that we need to add compared to slapadd, but the basic concept is identical. Since you’re on the client side of a running LDAP system, you will need to be able to authenticate yourself as a user who is allowed to add records to the directory. So before even attempting to add records, you should ensure that you have a user account with write permission to the directory. For more on this, see part 5 of this guide that discusses ACLs. For the time being, we’ll assume that you’re using the Manager login defined in the slapd.conf file.

The options that you’ll be most interested in for ldapadd are the following:

-D: the DN you want to use to authenticate with
-c: Continuation mode
-n: Dry run mode
-f: The LDIF file to use
-x: Simple authentication instead of the default, which is SASL (ignore if using SASL, obviously)
-W: Prompt user for password instead of requiring password be provided in plain text on command line
-h: LDAP host (if omitted, ldapadd will use the server in the PAM and NSS configurations)
-v: Verbose mode

As you can see, there are a lot more options here. The -c, -n, -f, and -v options function the same way they did in slapadd. I’ll focus instead on some of the new ones. The -x option should be used if you haven’t set up SASL authentication. This guide does not use SASL. It is supposed to be more secure than simple authentication, but it also introduces a lot more complexity. If it is not a necessity for you, I recommend not worrying about it. The -W option is also important if you’re not using SASL. Normally, ldapadd requires that a password be passed on the command line for authentication. While this is useful for scripts or automated tasks, it presents a security problem when you’re typing it in your shell. That command will be saved in your shell history, so that password will be sitting in a file in your home directory. The -W option lets you force ldapadd to prompt you instead, making it much more secure. The -h option is only required if you need to specify a different LDAP host than your system is configured to use. This is useful prior to setting up a connection or if you have multiple directories in your environment. Lastly, the -D option specifies the full DN of the user you want to connect as.

Now that you have all the options you need, lets create a file called newuser.ldif with a user account to add to LDAP.

dn: uid=testuser1,ou=People,dc=example,dc=com
cn: testuser1
objectClass: top
objectClass: posixAccount
objectClass: account
uid: testuser1
uidNumber: 500
gidNumber: 500
homeDirectory: /home/testuser1
loginShell: /bin/sh
userPassword: {SSHA}CkQ8nGKsYsb4vDhRyhCgzHasfHEZGLa0

This will create a test user account with a home directory, login shell, and UID/GID numbers. It will be placed in the People organizational unit in your directory. To use ldapadd to add this record in, first execute:

ldapadd -xWvcn -D "cn=Manager,dc=example,dc=com" -f newuser.ldif

This will perform a dry run of the file. You should see no errors and get the same results as with slapadd. Now rerun that same command without the -c and -n options. Your new record will now be in the directory. You should also be able to log into any LDAP-configured client as testuser1 with the password specified.

Initial Setup Shortcut

There is a nice shortcut for setting up your directory the first time with all the physical users on your hosts. The LDAP packages come with a set of scripts for converting existing users, complete with UIDs, GIDs, home directories, passwords, etc., into LDIF records. In CentOS, these scripts are located by default in /usr/share/openldap/migration. There are two versions of all the shell scripts in that directory: online and offline. The difference is whether the script assumes the LDAP server is online (so it will use ldapadd) or offline (so it will use slapadd). Each script will attempt to update the LDAP server immediately during execution. If you want to review the changes first, pick the incorrect script and you can see the LDIF file it creates before anything gets added. For instance, pick the offline version when your LDAP server is running, and it won’t be able to add anything into the directory.

To use these scripts, you must first tell them where in your directory to place the records. To do this, edit the migrate_common.ph file. There are two parameters you must set: $DEFAULT_MAIL_DOMAIN and $DEFAULT_BASE. These must be set according to your directory’s root name. Once that is done, you can simply run ./migrate_all_offline.sh and it will create a file in the /tmp directory called nis.ldif.xxxxx.  The last x’s are replaced by a random string. If you used a method that would fail, you can go look at this file and do a dry run to test it. You can still remove things from it as well if you don’t want to migrate local system users such as root or nobody.

Check back soon to see part 5, where I demonstrate how to configure ACLs to both enhance the security of the directory and provide specific users or groups with specific sets of permissions.