AD to LDAP

This how-to is the way I was able to install OpenLDAP and use it to authenticate from my Active Directory data. This is still an evolving process that is still in development. This should be enough to get you started in the right direction. Thanks to Norbert Klasen for all his help.

Software used: (Linux)
RedHat Linux 9.0
OpenLDAP 2.1.21
BerkeleyDB 4.1.25

Software needed, but was already on the system from the OS install:
OpenSSL
CyrusSASL

Software used: (Windows)
PWdump2
ActiveState Perl
Included Perl scripts (See Appendix B)
After installing and updating my RedHat system, I gathered all of the files listed above and untar’d them into /usr/src.

/usr/src/ldap/db-4.1.25
/usr/src/openldap-2.1.21

I then went to /usr/src/db-4.1.25/dist and ran:
./configure
make
make install
make clean

I had quite a bit of trouble getting OpenLDAP to compile with all of the options that I needed, but finally, I got it to work by doing the following:
*Note: I’m still having some trouble compiling on some systems. So YMMV. I’ll update this once I’ve figured out a better way.

Rename the current /usr/include/db.h file to db.h.bak.
Copy /usr/local/BerkeleyDB.4.1/include/db.h to /usr/include/db.h.
In /etc/ld.so.conf add the line: /usr/local/BerkeleyDB.4.1/lib.
Run ldconfig.
Copy all of the files from /usr/kerberos/include to /usr/include
Copy all of the files from /usr/src/openldap-2.1.21/include to /usr/include
Then, in the /usr/src/openldap-2.1.21/ directory, run the following as a single line:
env CPFLAGS=-I/usr/local/BerkeleyDB.4.1/include; export CPFLAGS; LDFLAGS=-L/usr/local/BerkeleyDB.4.1/lib; export LDFLAGS; ./configure –disable-ipv6 –with-cyrus-sasl –without-kerberos –enable-crypt –enable-lmpasswd

Then:
Make
Make depend
Make test
Make install
Make clean

Note: Throughout this how-to, we’ll assume you’re setting this up on a machine called ldap.test.net

Then it’s time to edit your slapd.conf.
(See Appendix A for my slapd.conf)

vi /usr/local/etc/openldap/slapd.conf and find the following line:
include /usr/local/etc/openldap/schema/core.schema
Now add this:
include /usr/local/etc/openldap/schema/cosine.schema
include /usr/local/etc/openldap/schema/nis.schema
Now find the line that starts with “suffix” and change to:
suffix “dc=test,dc=net”

and the line “rootdn” and change to:
rootdn “cn=Manager,dc=test,dc=net”

This is enough to get started, but you may want to change a lot of this later once you have it working to make sure it’s secure.

Start slapd (su root –c /usr/local/libexec/slapd)

Now to make our root. Copy this into a file called make_root.ldif:
dn: dc=test,dc=net
objectclass: dcObject
objectclass: organization
o: Example Company
dc: test

dn: cn=Manager,dc=test,dc=net
objectclass: organizationalRole
cn: Manager

Note: Make sure line 4’s value for dc (test) is the same as line 1’s value for dc (test).

Now import the file:
ldapadd -x -D “cn=Manager,dc=test,dc=net” -W -f make_root.ldif
Now to get the Active Directory data into you’re new LDAP server.

On a Windows domain controller while logged in as an administrator install ActiveState Perl and copy the perl script (Apendix B) and pwdump2 files to a secure directory. Open a command window and run this:
pwdump2.exe > passwd.txt
mirgrate.pl –b dc=test,dc=net passwd.txt users.ldif

You should now have a file (users.ldif) with all of your users in it. Move this file to your ldap server and execute this:
ldapadd -x -D “cn=Manager,dc=test,dc=net” -W -f users.ldif

You’ve just imported all of your AD data into LDAP. You can now authenticate all of your other systems against it.

Note: This is not yet ready for production!!! You’ll need to make sure you’ve hardened your machine (Bastille Linux is a good start.) and using some form of encryption/secure authentication (ssl). You have been warned.

Securing LDAP

One of the easiest steps you can take in securing LDAP is encrypting your “rootpw” in your slapd.conf. Use “slappasswd” for this task. By default slappasswd uses the {SSHA} option, so you’d enter:
slappasswd -s yourpassword
which will give you the following output: {SSHA}i+RR9IAmrGDC0+RogacHrKNqUHVP1w7p. Now just add this to your slapd.conf and restart slapd.

You now need to work a little OpenSSL magic. If you don’t have your own Certificate Authority (CA) you’ll have to create one. Although this sounds pretty sophisticated, its actully pretty simple. I’m going to clean this up soon, but for now, here are the commands:

cd /path/to/your/ssl/certs (probably /usr/local/etc/openldap or /usr/share/ssl/certs) and run the following commands:
openssl genrsa -des3 -out ca.key 1024
openssl req -new -x509 -days 999 -key ca.key -out ca.crt
openssl genrsa -des3 -out server.key 1024
openssl req -new -key server.key -out server.csr

mkdir -p demoCA/private
cp ca.key demoCA/private/cakey.pem
cp ca.crt demoCA/cacert.pem
mkdir demoCA/newcerts
touch demoCA/index.txt
echo “01” > demoCA/serial
openssl ca -policy policy_anything -in server.csr -out server.cert

To allow TLS-enabled connections you’ll need to configure your slapd.conf to use SSL. Add the following lines, making sure to use the path to your certs:
TLSCertificateFile /path/to/your/server.crt
TLSCertificateKeyFile /path/to/your/server.key

It will complain that your certificate is self-signed and therefore not valid unless you add the following line to your slapd.conf:
TLS_REQCERT allow

Now start it up:
slapd -h “ldaps:/// ldap://127.0.0.1:389”

Now you’ll have to configure your ldap.conf (/usr/local/etc/openldap/ldap.conf) so you can still use your client tools (ldapadd, ldapmodify, etc…) I added the following lines:
URI ldap://127.0.0.1
TLS_CACERT /path/to/certs/server.cert
TLS_KEY /usr/path/to/certs/server.key
TLS_REQCERT allow
More on this in a later update…

Appendix A: My slapd.conf:

# $OpenLDAP: pkg/ldap/servers/slapd/slapd.conf,v 1.23.2.8 2003/05/24 23:19:14 kurt Exp $
#
# See slapd.conf(5) for details on configuration options.
# This file should NOT be world readable.
#
include /usr/local/etc/openldap/schema/core.schema
include /usr/local/etc/openldap/schema/cosine.schema
include /usr/local/etc/openldap/schema/nis.schema
TLSCertificateFile /path/to/server.cert
TLSCertificateKeyFile /path/to/server.key
TLS_REQCERT allow

# Define global ACLs to disable default read access.

# Do not enable referrals until AFTER you have a working directory
# service AND an understanding of referrals.
#referral ldap://root.openldap.org

pidfile /usr/local/var/slapd.pid
argsfile /usr/local/var/slapd.args

# Load dynamic backend modules:
# modulepath /usr/local/libexec/openldap
# moduleload back_bdb.la
# moduleload back_ldap.la
# moduleload back_ldbm.la
# moduleload back_passwd.la
# moduleload back_shell.la

# Sample security restrictions
# Require integrity protection (prevent hijacking)
# Require 112-bit (3DES or better) encryption for updates
# Require 63-bit encryption for simple bind
# security ssf=1 update_ssf=112 simple_bind=64

# Sample access control policy:
# Root DSE: allow anyone to read it
# Subschema (sub)entry DSE: allow anyone to read it
# Other DSEs:
# Allow self write access
# Allow authenticated users read access
# Allow anonymous users to authenticate
# Directives needed to implement policy:
# access to dn.base=”” by * read
# access to dn.base=”cn=Subschema” by * read
# access to *
# by self write
# by users read
# by anonymous auth
#
# if no access controls are present, the default policy is:
# Allow read by all
#
# rootdn can always write!

#######################################################################
# ldbm database definitions
#######################################################################

database bdb
suffix “dc=test,dc=net”
rootdn “cn=Manager,dc=test,dc=net”
# Cleartext passwords, especially for the rootdn, should
# be avoid. See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
rootpw {SSHA}i+RR9IAmrGDC0+RogacHrKNqUHVP1w7p
# The database directory MUST exist prior to running slapd AND
# should only be accessible by the slapd and slap tools.
# Mode 700 recommended.
directory /usr/local/var/openldap-data
# Indices to maintain
index objectClass eq

Appendix B: migrate.pl:
#!/usr/bin/perl
# Copyright (c) 2000, Norbert Klasen.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# o Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# o Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# o Neither the name of the Universitaet Tuebingen nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS
# IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Password migration tool. Migrates dump from Windows NT SAM or Active
# Directory to rfc2307 ldif file.
# See http://www.webspan.net/~tas/pwdump2/ for pwdump

use strict;
use Getopt::Std;
use vars qw/ $opt_u $opt_g $opt_d $opt_s $opt_b $gidNumber $homeDirectoryBase $loginShell $basedn/;

if (!getopts(‘uig:d:s:b:’))
{
print “migrate_pwdump: converts Windows SAM dump to rfc2307 ldif file\n”;
print “usage: [-u] [-g group] [-d homebase] [-s shell] [-b basedn] pwdump-file\n”;
print ” -u generate ldif file for changing userPassword attribute only\n”;
exit;
}

if ( $opt_g ) {
$gidNumber = $opt_g;
} else {
$gidNumber = 100;
}

if ( $opt_d ) {
$homeDirectoryBase = $opt_d;
} else {
$homeDirectoryBase = “/home/”;
}

if ( $opt_s ) {
$loginShell = $opt_s;
} else {
$loginShell = “/bin/bash”;
}

if ( $opt_b ) {
$basedn = $opt_b;
} else {
$basedn = “ou=Users,dc=test,dc=net”;
}
while ( <> ) {
my ($name, $uidNumber, $lanmanger_hash, $nt_hash, $account_flags, $last_change_time, $remainder) = split /:/, $_;
next if $name =~ /\$$/; #computer accounts shouldn’t be included
print “dn: uid=$name,$basedn\n”;
if ( $opt_u ) {
print “changetype: modify\n”;
print “replace: userPassword\n”;
print “userPassword: {lanman}$lanmanger_hash\n”;
} else {
print “objectclass: top\n”;
print “objectclass: account\n”;
print “objectclass: posixAccount\n”;
#posixAccount MUST
print “cn: $name\n”;
print “uid: $name\n”;
print “uidNumber: $uidNumber\n”;
print “gidNumber: $gidNumber\n”;
#print “homeDirectory: $homeDirectoryBase$name\n”;
#posixAccount MAY
print “userPassword: {lanman}$lanmanger_hash\n”;
#print “loginShell: $loginShell\n”;
}
print “\n”;
}