<?xml version="1.0" standalone="no"?>

<!--
  Kerberos 5 installation guide on Debian GNU

  http://techpubs.spinlocksolutions.com/dklar/kerberos.xml
  http://techpubs.spinlocksolutions.com/dklar/kerberos.html
  http://techpubs.spinlocksolutions.com/dklar/kerberos.tgz

  (C) 2006-2010 Davor Ocelic, docelic@spinlocksolutions.com

  SPINLOCK, http://www.spinlocksolutions.com/ - advanced
  infrastructure-based Unix solutions for commercial and
  education sectors.


 This documentation is free; you can redistribute it and/or modify
 it under the terms of the &GNU; General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 It is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.


  To build the HTML version of the article, download
  http://techpubs.spinlocksolutions.com/dklar/kerberos.tgz , 
  save the following as Makefile and run 'make kerberos.html':

%.html: %.xml
	xsltproc -o $@ \
	-stringparam html.stylesheet DKLAR.css \
	/usr/share/xml/docbook/stylesheet/nwalsh/html/docbook.xsl $<

-->

<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
	"docbook/docbookx.dtd"[ 

	<!ENTITY DEB "<ulink url='http://www.debian.org/'>Debian GNU</ulink>">
	<!ENTITY GNU "<ulink url='http://www.gnu.org/'>GNU</ulink>">
	<!ENTITY KRB "<ulink url='http://web.mit.edu/kerberos/'>MIT Kerberos</ulink>">
	<!ENTITY LDA "<ulink url='http://www.openldap.org/'>OpenLDAP</ulink>">
	<!ENTITY AFS "<ulink url='http://www.openafs.org/'>OpenAFS</ulink>">
	<!ENTITY RAD "<ulink url='http://www.freeradius.org/'>FreeRADIUS</ulink>">
	<!ENTITY DLH "<ulink url='http://colt.projectgamma.com/debian-ldap-howto/'>Debian-LDAP Howto</ulink>">
	<!ENTITY PAM "<ulink url='http://www.kernel.org/pub/linux/libs/pam/'>Linux-PAM</ulink>">
	<!ENTITY PSY "<ulink url='http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/sag-configuration-file.html'>PAM Configuration File Syntax</ulink>">
	<!ENTITY NSS "<ulink url='http://www.gnu.org/software/libc/manual/html_node/Name-Service-Switch.html'>NSS</ulink>">
	<!ENTITY SUN "<ulink url='http://www.sun.com/'>Sun Microsystems</ulink>">
	<!ENTITY HDL "<ulink url='http://www.pdc.kth.se/heimdal/'>Heimdal Kerberos</ulink>">
	<!ENTITY DOCBK "<ulink url='http://www.docbook.org/'>DocBook</ulink>">
	<!ENTITY SHELL_GLOBBING "<ulink url='http://tldp.org/LDP/abs/html/globbingref.html'>shell globbing</ulink>">
	<!ENTITY KRBC "<ulink url='http://www.kerberos.org/'>Kerberos consortium</ulink>">
	<!ENTITY GQCL "<ulink url='http://sourceforge.net/projects/gqclient'>Gq</ulink>">
	<!ENTITY W2LD "<ulink url='http://www.web2ldap.de/'>web2ldap</ulink>">
	<!ENTITY LUMA "<ulink url='http://luma.sourceforge.net/'>Luma</ulink>">
	<!ENTITY JXPL "<ulink url='http://jxplorer.org/'>jXplorer</ulink>">
	<!ENTITY ADSS "<ulink url='http://directory.apache.org/studio/'>Apache Directory Studio</ulink>">
	<!ENTITY PRINCIPAL "<ulink url='http://kerberos.org/software/tutorial.html#1.3.2'>principal</ulink>">
	<!ENTITY SECRET_KEY "<ulink url='http://kerberos.org/software/tutorial.html#1.3.4'>secret key</ulink>">
	<!ENTITY KERBEROS_DATABASE "<ulink url='http://kerberos.org/software/tutorial.html#1.3.5.1'>Kerberos database</ulink>">
	<!ENTITY REALM "<ulink url='http://kerberos.org/software/tutorial.html#1.3.1'>realm</ulink>">
	<!ENTITY KERBEROS-SPECIFIC "<ulink url='http://kerberos.org/software/tutorial.html#1.3.5.1'>Kerberos-specific</ulink>">
	<!ENTITY KDC "<ulink url='http://kerberos.org/software/tutorial.html#1.3.5'>KDC</ulink>">
	<!ENTITY TGT "<ulink url='http://kerberos.org/software/tutorial.html#1.5.1'>TGT</ulink>">
	<!ENTITY KERBEROS_RELEASE "<ulink url='http://web.mit.edu/Kerberos/dist/index.html'>Kerberos release</ulink>">

	<!ENTITY SL "<ulink url='http://www.spinlocksolutions.com/'>Spinlock Solutions</ulink>">
	<!ENTITY DKLAR_DEB "<ulink url='http://techpubs.spinlocksolutions.com/dklar/debian.html'>Debian GNU Guide</ulink>">
	<!ENTITY DKLAR_KRB "<ulink url='http://techpubs.spinlocksolutions.com/dklar/kerberos.html'>MIT Kerberos 5 Guide</ulink>">
	<!ENTITY DKLAR_LDA "<ulink url='http://techpubs.spinlocksolutions.com/dklar/ldap.html'>OpenLDAP Guide</ulink>">
	<!ENTITY DKLAR_AFS "<ulink url='http://techpubs.spinlocksolutions.com/dklar/afs.html'>OpenAFS Guide</ulink>">
	<!ENTITY DKLAR_RAD "<ulink url='http://techpubs.spinlocksolutions.com/dklar/radius.html'>FreeRADIUS Guide</ulink>">
		<!ENTITY MLS "<ulink url='http://www.openldap.org/lists/'>http://www.openldap.org/lists/</ulink>">
		<!ENTITY DOC "<ulink url='http://www.openldap.org/doc/admin24/'>http://www.openldap.org/doc/admin24/</ulink>">
]>

<article id='debian-ldap'>

<articleinfo>

	<title>Debian GNU: Setting up OpenLDAP</title>
	<titleabbrev>debian-ldap</titleabbrev>

	<copyright>
		<year>2006-2010</year>
		<holder>Davor Ocelic</holder>
	</copyright>

	<authorgroup>
		<author>
			<firstname>Davor</firstname><surname>Ocelic</surname>
			<email>docelic@spinlocksolutions.com</email>
			<affiliation><ulink url="http://www.spinlocksolutions.com/">SPINLOCK</ulink> &mdash; advanced GNU/Linux and Unix solutions for commercial and education sectors.</affiliation>
		</author>
	</authorgroup>

	<legalnotice>
    <para>
    Last update: Mar 22, 2010. &mdash; Maintain everything up to date, add links to other documentation
    </para>
		<para>
		This documentation is free; you can redistribute it and/or modify
		it under the terms of the &GNU; General Public License as published by
		the Free Software Foundation; either version 2 of the License, or
		(at your option) any later version.
		</para><para>
		It is distributed in the hope that it will be useful,
		but WITHOUT ANY WARRANTY; without even the implied warranty of
		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
		GNU General Public License for more details.
		</para>
	</legalnotice>

	<abstract>
		<para>
		The purpose of this article is to give you a straight-forward,
		Debian-friendly way of installing and configuring 
		OpenLDAP.
		</para><para>
		By the end of this guide, you will have a functional LDAP
		server that will serve as a central authentication system
		for user logins onto all machines in the network, without
		the need to manually create users' accounts on individual machines.
		</para><para>
		However, for improved authentication security and a true networked
		solution, it is recommended to use LDAP in combination with Kerberos,
		with a matching Kerberos setup explained in &DKLAR_KRB;,
		</para><para>
		This article is part of &SL;'s practical 5-piece introductory series
		to infrastructure-based Unix networks,
		containing &DKLAR_DEB;,  &DKLAR_KRB;,  &DKLAR_LDA;,  &DKLAR_AFS; and
		&DKLAR_RAD;.
		</para>
	</abstract>

</articleinfo>


<section id="intro">
<title>Introduction</title>
<para>
LDAP is a service that has been traditionally captivating system
administrators' and advanced users' interest, but its (seemingly or
not) high entry barrier and infrastructure requirements have been
preventing many from using it.
</para><para>
LDAP has already been the topic of numerous publications.
Here, we will present only the necessary summary; enough information
to establish the context and to achieve practical results.
</para><para>
You do not need to follow any external links; however, the links have
been provided both throughout the article and listed all together at
the end, to serve as pointers to more precise technical treatment of
individual topics.
</para>

<section id="intro-krb">
<title>The role of LDAP within a network</title>
<para>
	<inlinemediaobject>
		<imageobject><imagedata fileref="images/logo-openldap.png"
			format="JPG" width="120px" scalefit="1" /></imageobject>
	</inlinemediaobject>
	OpenLDAP is an open source implementation of the Lightweight
	Directory Access Protocol. Directory itself is a tree-structured,
	read-optimized database.  Yellow pages or a phonebook are good
	associations to have in mind, even though LDAP is much more powerful.
	</para><para>
	We will use OpenLDAP to provide a central authentication location for 
	user logins anywhere on the network, with their home directories
	being automatically created on their first access to individual machines. 
	</para><para>
	This guide can be followed standalone to make OpenLDAP both perform
	authentication and serve user meta data. However, using LDAP for
	authentication as shown here is not secure due to plain text connections
	made to the LDAP server and passwords travelling over the wire.
	It is therefore advised to use LDAP in combination with a superior and
	secure network authentication mechanism Kerberos, which is explained in
	another article from the series, the &DKLAR_KRB;.
	</para><para>
	That said, let's move onto our LDAP setup.
	</para><para>
	From a technical perspective, LDAP directory consists of a set of
	hierarchically organized
	<emphasis>entries</emphasis>.
	Each entry belongs to certain <emphasis>Object Classes</emphasis> and
	contains various <literal><replaceable>key=value</replaceable></literal>
	pairs called <emphasis>attributes</emphasis>.
	</para><para>
	Each entry is uniquely identified by a 
	<emphasis>Distinguished name</emphasis> ("DN"). DN is formed as a list of 
	components, separated by commas, that provide "full path" to the entry,
	starting from the top of the tree. For example, company Example, Inc. 
	would have the root of the tree in
	<literal>dc=<replaceable>example</replaceable>,dc=<replaceable>com</replaceable></literal>. A person employed by Example, Inc.
	would then have a corresponding LDAP entry with DN
	<literal>cn=<replaceable>person</replaceable>,ou=People,dc=<replaceable>example</replaceable>,dc=<replaceable>com</replaceable></literal>.
	</para><para>
	Which attributes may or must be present in an entry is governed by the
	entry's objectClasses.
	</para><para>
	You might notice that the individual components of the DN, such as
	<literal>cn=<replaceable>person</replaceable></literal> above, are also
	formed as <literal><replaceable>key=value</replaceable></literal> pairs.
	Those "keys", <literal>cn</literal>, <literal>ou</literal>
	and <literal>dc</literal>, stand for <literal>Common Name</literal>,
	<literal>Organizational Unit</literal> and
	<literal>Domain Component</literal>. They are a part of every-day LDAP 
	terminology that you will get used to.
	</para><para>
	ObjectClasses, attributes, syntaxes, matching rules and other details
	of the tree structure are configurable and loaded at LDAP server startup
	by reading the <emphasis>schema</emphasis> files defined in 
	<filename>/etc/ldap/slapd.conf</filename>.
	</para><para>
	Let's quickly identify LDAP-specific elements in our setup:
</para>

	<itemizedlist>
	<listitem><para>
	LDAP is not in any way related to traditional system usernames
	or other data. However, part of its functionality in our setup 
	will consist in storing information traditionally found in Unix files
	<filename>/etc/passwd</filename> and <filename>/etc/group</filename>,
	thus making that data network-accessible at a centralized location.
	</para><para>
	People's login names will be used in pairing people with the corresponding
	information in the LDAP tree. For example, username <literal><replaceable>person</replaceable></literal>
	will map to an LDAP entry
	<literal>uid=<replaceable>person</replaceable>,ou=People,dc=<replaceable>example</replaceable>,dc=<replaceable>com</replaceable></literal>.
	</para></listitem>
	<listitem><para>
	LDAP can be configured to contain user passwords. Passwords can be used
	both for authenticating as specific users and gaining access to protected
	entries, and for verifying whether the user knows the correct password.
	</para><para>
	When a user opens a LDAP client and moves to browse the directory, 
	his DN and password are used to establish the identity and access privileges.
	When LDAP is configured to perform user authentication, his DN and
	password are only used to perform a connection to the LDAP directory &mdash;
	successful connection ("bind") implies the user knew the correct
	password.
	</para></listitem>
	</itemizedlist>

<para>
	You can find the complete OpenLDAP documentation at the &LDA; website.
	For an authoritative OpenLDAP book, see Gerald Carter's
	<literal>LDAP System Administration</literal> by O'Reilly.
</para>

</section>

<section>
<title>Glue layers: integrating LDAP with system software</title>

<section><title>NSS</title>
<para>
	On all GNU/Linux-based platforms, &NSS; is available for network data
	retrieval configuration. &NSS; is an implementation of the
	<literal>Name Service Switch</literal> mechanism.
	</para><para>
	NSS will allow for inclusion of LDAP into the "user data" path
	of all services, regardless of whether they natively support LDAP 
	or not.
	</para><para>
	You can find the proper introduction (and complete documentation)
	on the &NSS; website.
	Also take a look at the 
	<citerefentry>
		<refentrytitle>nsswitch.conf</refentrytitle>
		<manvolnum>5</manvolnum>
	</citerefentry>
	manual page.
</para>
</section>

<section><title>PAM</title>
<para>
	Likewise, on all GNU/Linux-based platforms, another piece of the puzzle,
	&PAM;, is available for service-specific authentication configuration.
	&PAM; is an implementation of PAM
	("<literal>Pluggable Authentication Modules</literal>") from &SUN;.
	</para><para>
	Network services, instead of having hard-coded authentication interfaces
	and decision methods, invoke PAM through a standard, pre-defined interface.
	It is then up to PAM to perform any and all authentication-related
	work, and report the result back to the application.
	</para><para>
	Exactly how PAM reaches the decision is none of the service's business.
	In traditional set-ups, that is most often done by asking and verifying
	usernames and passwords. In advanced networks, that could be retina
	scans or &mdash; Kerberos tickets, as explained in another article
	from the series, &DKLAR_KRB;.
	</para><para>
	You can find the proper introduction (and complete documentation)
	on the &PAM; website. Pay special attention to the &PSY; page.
	Also take a look at the 
	<citerefentry>
		<refentrytitle>Linux-PAM</refentrytitle>
		<manvolnum>7</manvolnum>
	</citerefentry>
	and
	<citerefentry>
		<refentrytitle>pam</refentrytitle>
		<manvolnum>7</manvolnum>
	</citerefentry>
	manual pages.
</para>
</section>
</section>

<section id="conventions">
<title>Conventions</title>
<para>
It's quite disappointing when you are not able to follow the instructions
found in the documentation. Let's agree on a few points before going down
to work:
</para>

<itemizedlist>
<listitem><para>
	Our platform of choice, where we will demonstrate a practical setup,
	will be &DEB;.
</para></listitem>
<listitem><para>
	Install <application>sudo</application>. Sudo is a program that will allow
	you to carry out system administrator tasks from your normal user account.
	All the examples in this article requiring root privileges use
	<application>sudo</application>, so you will be able to copy-paste them
	to your shell.
<programlisting>
su -c 'apt-get install sudo'
</programlisting>
If asked for a password, type in the root user's password.
	</para><para>
	To configure sudo, add the following line to your
	<filename>/etc/sudoers</filename>, replacing <literal>$USERNAME</literal>
	with your login name:
<programlisting>
$USERNAME ALL=(ALL) NOPASSWD: ALL
</programlisting>
</para></listitem>
<listitem><para>
	Debian packages installed during the procedure
	will ask us a series of questions through the so-called
	<emphasis>debconf</emphasis> interface. To configure debconf to a 
	known state, run:
<programlisting>
sudo dpkg-reconfigure debconf
</programlisting>
When asked, answer <emphasis>interface</emphasis>=<literal>Dialog</literal>
and <emphasis>priority</emphasis>=<literal>low</literal>.
</para></listitem>
<listitem><para>
	Monitoring log files is crucial in detecting problems. The straight-forward,
	catch-all routine to this is opening a terminal and running:
<programlisting>
cd /var/log; sudo tail -F daemon.log sulog user.log auth.log debug kern.log syslog dmesg messages kerberos/{krb5kdc,kadmin,krb5lib}.log
</programlisting>
	</para><para>
	The command will keep printing log messages to the screen as they arrive.
</para></listitem>
<listitem><para>
	Our test system will be called <literal>monarch.spinlock.hr</literal> and
	have an IP address of <literal>192.168.7.12</literal>. Both the server and
	the client will be installed on the same machine. However, to differentiate
	between client and server roles where relevant, the client will be referred
	to as <literal>monarch.spinlock.hr</literal> and the server as
	<literal>ldap1.spinlock.hr</literal>. The following addition will be 
	made to <filename>/etc/hosts</filename> to completely support this
	scheme:
<screen>
<replaceable>192.168.7.12</replaceable>	<replaceable>monarch.spinlock.hr</replaceable> <replaceable>monarch</replaceable> krb1.<replaceable>spinlock.hr</replaceable> krb1 ldap1.<replaceable>spinlock.hr</replaceable> ldap1
</screen>

<caution><para>
Note that in some Debian installations the system's network hostname is
assigned to the localhost address <literal>127.0.0.1</literal>. This can
and will cause problems for network operations, so make sure that your
"localhost" entry in <filename>/etc/hosts</filename> looks exactly like
the following (nothing more, nothing less):

<screen>
127.0.0.1  localhost  localhost.localdomain
</screen>
</para></caution>

<para>
Finally, test that the network setup is as expected. Pinging the hostnames
should report proper FQDNs and IPs as shown:
<screen>
<userinput>ping -c1 localhost</userinput>
PING localhost (127.0.0.1) 56(84) bytes of data.
....

<userinput>ping -c1 <replaceable>monarch</replaceable></userinput>
PING <replaceable>monarch.spinlock.hr</replaceable> (<replaceable>192.168.7.12</replaceable>) 56(84) bytes of data.
....

<userinput>ping -c1 ldap1</userinput>
PING krb1.<replaceable>spinlock.hr</replaceable> (<replaceable>192.168.7.12</replaceable>) 56(84) bytes of data.
....
</screen>
</para>
</para></listitem>
</itemizedlist>

</section>

</section>

<section id="ldap"><title>OpenLDAP</title>

<section id="ldap-install"><title>Server installation</title>
<para>
OpenLDAP's server component is called <command>slapd</command>, and is 
basically all that we will need.

<programlisting>
sudo apt-get install slapd ldap-utils
</programlisting>

Debconf answers for reference:

<screen>
Omit OpenLDAP server configuration? <userinput>No</userinput>

DNS domain name: <userinput><replaceable>spinlock.hr</replaceable></userinput>

Organization name? <userinput><replaceable>spinlock.hr</replaceable></userinput>

Administrator password: <userinput><replaceable>PASSWORD</replaceable></userinput>

Confirm password: <userinput><replaceable>PASSWORD</replaceable></userinput>

Database backend to use: <userinput>HDB</userinput>

Do you want the database to be removed when slapd is purged? <userinput>No</userinput>

Allow LDAPv2 protocol? <userinput>No</userinput>
</screen>

As soon as the installation is done, the OpenLDAP server
(command <command>slapd</command>) will start.
</para>
<!--
<para>
In case you'll ever want to remove the OpenLDAP installation completely and
start anew, use the following set of commands:
<programlisting>
sudo invoke-rc.d slapd stop
sudo apt-get -purge remove slapd libpam-nss libpam-ldap
sudo rm -rf /etc/ldap/ /etc/libnss-ldap.conf /etc/pam_ldap.conf
sudo rm -rf /var/lib/ldap/
</programlisting>
Note that removing nss and pam configuration files will also require 
removal of the modules from files <filename>/etc/nsswitch.conf</filename> and
<filename>/etc/pam.d/common-*</filename>, and eventually stopping of the 
Nscd service by running <userinput>sudo invoke-rc.d nscd stop</userinput>.
</para>
-->
</section>

<section id="ldap-initial-cfg"><title>Initial configuration</title>

<para>
Our OpenLDAP server is already running, so let's first configure 
<filename>/etc/ldap/ldap.conf</filename>, a common configuration file
for all LDAP clients. This will allow us to run
<command>ldapsearch</command> and other commands without having to list
all the basic parameters by hand each time.
</para><para>
Enable the following two lines in <filename>/etc/ldap/ldap.conf</filename>,
creating the file if necessary:
<screen>
BASE  dc=<replaceable>spinlock</replaceable>, dc=<replaceable>hr</replaceable>
URI ldap://<replaceable>192.168.7.12</replaceable>/
</screen>

</para><para>
Then, let's edit the server's configuration file in 
<filename>/etc/ldap/slapd.conf</filename> to tune its behavior.

</para><para>
Make sure all the schema files are enabled:
<screen>
include         /etc/ldap/schema/core.schema
include         /etc/ldap/schema/cosine.schema
include         /etc/ldap/schema/nis.schema
include         /etc/ldap/schema/inetorgperson.schema
</screen>

Change the verbosity level from <literal>0</literal> or
"<literal>none</literal>" to <literal>256</literal>:
<screen>
loglevel 256
</screen>

Search for line "<literal>index           objectClass eq</literal>" and
add another search index. In particular combinations, it may be possible
to receive no results when the searched entries are not indexed, so this
step is important:
<screen>
index           objectClass eq
index           uid         eq
</screen>

To make the new index option apply, run the following commands:
<programlisting>
sudo invoke-rc.d slapd stop
sudo slapindex
sudo chown -R openldap:openldap /var/lib/ldap
sudo invoke-rc.d slapd start
</programlisting>

</para></section>

<section id="ldap-test1"><title>Initial test</title><para>

It's already the time to test the installation. Our OpenLDAP server
does not contain much information, but a basic read operation can
be performed normally.
</para><para>
In LDAP terms, read operation is called a "search". To perform a search
using generic command-line utilities, we have <command>ldapsearch</command>
and <command>slapcat</command> available.
</para><para>
<command>Ldapsearch</command> (and other LDAP utilities prefixed "ldap")
perform operations "online", using the LDAP protocol.
</para><para>
<command>Slapcat</command> (and other OpenLDAP utilities prefixed "slap")
perform operations "offline", directly by opening files on the local
filesystem. For this reason, they can only be ran locally on the
OpenLDAP server and they require administrator privileges. When they
involve writing to the database, the OpenLDAP server usually needs to
be stopped first.
</para><para>
In the output of the two search commands, you will notice two LDAP
entries, one representing the top level element in the three, and
another representing the LDAP administrator's entry.
In the <command>slapcat</command> output, notice the
extra attributes not printed with <command>ldapsearch</command>.
One of those is <literal>userPassword</literal>, which is not shown to
anonymous readers due to the appropriate default access restrictions in
<filename>/etc/ldap/slapd.conf</filename>.
</para><para>
<screen>
<userinput>ldapsearch -x</userinput>

# extended LDIF
#
# LDAPv3
# base &lt;<replaceable>dc=spinlock, dc=hr</replaceable>&gt; (default) with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# <replaceable>spinlock.hr</replaceable>
dn: dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable>
objectClass: top
objectClass: dcObject
objectClass: organization
o: <replaceable>spinlock.hr</replaceable>
dc: <replaceable>spinlock</replaceable>

# admin, <replaceable>spinlock.hr</replaceable>
dn: cn=admin,dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable>
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator

# search result
search: 2
result: 0 Success

# numResponses: 3
# numEntries: 2
</screen>

<screen>
<userinput>sudo slapcat</userinput>

dn: dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable>
objectClass: top
objectClass: dcObject
objectClass: organization
o: <replaceable>spinlock.hr</replaceable>
dc: <replaceable>spinlock</replaceable>
structuralObjectClass: organization
entryUUID: 350a2db6-87d3-102c-8c1c-1ffeac40db98
creatorsName:
modifiersName:
createTimestamp: 20080316183324Z
modifyTimestamp: 20080316183324Z
entryCSN: 20080316183324.797498Z#000000#000#000000

dn: cn=admin,dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable>
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword:: e2NyeXB0fVdSZDJjRFdRODluNHM=
structuralObjectClass: organizationalRole
entryUUID: 350b330a-87d3-102c-8c1d-1ffeac40db98
creatorsName:
modifiersName:
createTimestamp: 20080316183324Z
modifyTimestamp: 20080316183324Z
entryCSN: 20080316183324.804398Z#000000#000#000000
</screen>

</para></section>

<section>
<title>Creating basic tree structure</title>
<para>
As explained, the LDAP database is structured as a tree. The top level
element in the tree for your organization is often its domain
name. In case of a domain <literal>spinlock.hr</literal>, the toplevel
tree element would be <literal>dc=spinlock,dc=hr</literal>.
</para><para>
On the next level below, an organization is often divided into 
"organizational units", such as people, groups, hosts, services,
networks, protocols, etc.
</para><para>
Accordingly, to support people's Unix "meta data" in our LDAP directory, 
we will be interested in creating two of the mentioned organizational units, 
<literal>People</literal> and <literal>Group</literal>. The two
will roughly correspond to the Unix
<filename>/etc/passwd</filename> and
<filename>/etc/group</filename> files.
</para><para>
Ldap data is interchanged in a textual format called LDIF. Command-line
LDAP utilities receive and produce data in this format. Note that the
LDIF stream can also contain commands, such as for adding, modifying or
removing LDAP entries.
</para><para>
Knowing this, we'll put together a simple LDIF file,
<filename>/var/tmp/ou.ldif</filename>, that will instruct
the server to add the two organizational units.
Pay attention to the empty line separating the entries:

<screen>
dn: ou=People,dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable>
ou: People
objectClass: organizationalUnit

dn: ou=Group,dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable>
ou: Group
objectClass: organizationalUnit
</screen>

To load the LDIF file into the server, let's show an example using the
offline tool, <command>slapadd</command>:

<programlisting>
sudo invoke-rc.d slapd stop
sudo slapadd -c -v -l /var/tmp/ou.ldif
sudo invoke-rc.d slapd start
</programlisting>

Let's use <command>ldapsearch</command> to verify the entries have
been created.
<screen>
<userinput>ldapsearch -x ou=people</userinput>

# extended LDIF
#
# LDAPv3
# base &lt;<replaceable>dc=spinlock, dc=hr</replaceable>&gt; (default) with scope subt
# filter: ou=people
# requesting: ALL
#

# People, <replaceable>spinlock.hr</replaceable>
dn: ou=People,dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable>
ou: People
objectClass: organizationalUnit

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
</screen>
</para></section>

<section>
<title>Creating user accounts</title>
<para>
In the same manner we've created the two organizational units, let's create
our first group and a person belonging to it. Again, we approach the
problem by constructing and loading an LDIF file, 
<filename>/var/tmp/user1.ldif</filename>, paying attention to
the empty line separating the entries:

<screen>
dn: cn=<replaceable>mirko</replaceable>,ou=group,dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable>
cn: <replaceable>mirko</replaceable>
gidNumber: <replaceable>20000</replaceable>
objectClass: top
objectClass: posixGroup

dn: uid=<replaceable>mirko</replaceable>,ou=people,dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable>
uid: <replaceable>mirko</replaceable>
uidNumber: <replaceable>20000</replaceable>
gidNumber: <replaceable>20000</replaceable>
cn: <replaceable>Mirko</replaceable>
sn: <replaceable>Mirko</replaceable>
objectClass: top
objectClass: person
objectClass: posixAccount
objectClass: shadowAccount
loginShell: /bin/bash
homeDirectory: /home/<replaceable>mirko</replaceable>
</screen>

To load the LDIF file into the server, let's show an example using the
online tool, <command>ldapadd</command>. Since, as said previously,
<command>ldapadd</command> uses the LDAP protocol, we'll have to bind
to the server as system administrator and type in the correct admin
password (defined during <application>slapd</application> installation):

<screen>
<userinput>ldapadd -c -x -D cn=admin,dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable> -W -f /var/tmp/user1.ldif</userinput>

Enter LDAP Password: <userinput><replaceable>PASSWORD</replaceable></userinput>

adding new entry "cn=<replaceable>mirko</replaceable>,ou=group,dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable>"

adding new entry "uid=<replaceable>mirko</replaceable>,ou=people,dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable>"

</screen>

Now to define the new user's password, let's run an online tool <command>ldappasswd</command>. (This step is not needed if you plan to use LDAP in combination with Kerberos as explained in &DKLAR_KRB;.)

</para>

<para>
<screen>
<userinput>ldappasswd -x -D cn=admin,dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable> -W -S uid=<replaceable>mirko</replaceable>,ou=people,dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable></userinput>

New password: <userinput><replaceable>NEW USER PASSWORD</replaceable></userinput>

Re-enter new password: <userinput><replaceable>NEW USER PASSWORD</replaceable></userinput>

Enter LDAP Password:  <userinput><replaceable>ADMIN PASSWORD</replaceable></userinput>

Result: Success (0)
</screen>

<note><para>
You might notice that all entries always have to be "fully qualified" and that
you cannot omit the suffix (dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable>) or other components of the DN. This often leads to command line examples that are long and cryptic, and look just like boring, unnecessary
work. If you percieve that as a problem, you'll solve it by either getting accustomed to it to the point of not noticing it any more, or you'll switch to using graphical LDAP clients that fill in most of that information for you.
</para></note>

Now let's use <command>ldapsearch</command> to verify the user entry
has been created. Note that the password field, <literal>userPassword</literal>,
will not be shown even if we created it, due to the default access
restrictions in <filename>/etc/ldap/slapd.conf</filename>.
<screen>
<userinput>ldapsearch -x uid=<replaceable>mirko</replaceable></userinput>

# extended LDIF
#
# LDAPv3
# base &lt;<replaceable>dc=spinlock, dc=hr</replaceable>&gt; (default) with scope subtree
# filter: uid=<replaceable>mirko</replaceable>
# requesting: ALL
#

# <replaceable>mirko</replaceable>, people, <replaceable>spinlock.hr</replaceable>
dn: uid=<replaceable>mirko</replaceable>,ou=people,dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable>
uid: <replaceable>mirko</replaceable>
uidNumber: <replaceable>20000</replaceable>
gidNumber: <replaceable>20000</replaceable>
cn: <replaceable>Mirko</replaceable>
sn: <replaceable>Mirko</replaceable>
objectClass: top
objectClass: person
objectClass: posixAccount
loginShell: /bin/bash
homeDirectory: /home/<replaceable>mirko</replaceable>

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
</screen>

<emphasis role='bold'>Congratulations! You now have a working LDAP setup</emphasis>.
</para></section>

<!--
<section>
<title>Graphical LDAP browsers</title>
<para>
While the LDIF format shown represents the basis of data interchange in LDAP,
for day to day work a graphical client may be preferred. 
</para><para>
Surprisingly, there are many LDAP GUI clients, but the large majority of
them is just non-functional or unusable for one reason or another.
These include, but are not limited to, &GQCL;, &LUMA;, lat and gtkol-ldap.
</para>
<para>
Two heavier LDAP GUI clients are &JXPL; and &ADSS;. jExplorer claims to have
bells and whistles, but is traditionally fragile and always finds one or
more astonishing reasons why it won't work on your machine. Apache Directory
Studio is the most promising, but is available for x86 and amd64 only, isn't
available in Debian archives, its package size is 92 MB, and the website
currently lists a workaround you have to apply to get it running on
certain Gtk versions. Go figure.
</para>
<para>
</para>
</section>
-->


<section id="NSS_configuration"><title>NSS configuration</title><para>
Now that we have a new user created in LDAP, we should allow the system
to see it. For example, let's test for existence of users
<literal>root</literal> and <literal>mirko</literal>. The administrator
will be present, while <literal>mirko</literal> will not:

<screen>
<userinput>id root</userinput>
uid=0(root) gid=0(root) groups=0(root)

<userinput>id <replaceable>mirko</replaceable></userinput>
id: <replaceable>mirko</replaceable>: No such user
</screen>

To enable the system see LDAP accounts, we need to install
<application>libnss-ldap</application> (which may automatically install libpam-ldap as well) and nscd:

<programlisting>
sudo apt-get install libnss-ldap nscd
</programlisting>

All debconf answers for reference:

<screen>
LDAP server URI: <userinput>ldap://<replaceable>192.168.7.12</replaceable>/</userinput> (Note the "ldap://", NOT "ldapi://"!)

Distinguished name of the search base: <userinput><replaceable>dc=spinlock,dc=<replaceable>hr</replaceable></replaceable></userinput>

LDAP version to use: <userinput>3</userinput>

Does the LDAP database require login? <userinput>No</userinput>

Special LDAP privileges for root? <userinput>No</userinput>

Make the configuration file readable/writeable by its owner only? <userinput>No</userinput>

Allow LDAP admin account to behave like local root? <userinput>Yes</userinput>

Make local root Database admin. <userinput>No</userinput>

Does the LDAP database require login? <userinput>No</userinput>

LDAP administrative account: <userinput>cn=admin,dc=h15,dc=ri</userinput>

LDAP administrative password: <userinput><replaceable>PASSWORD</replaceable></userinput>

Local crypt to use when changing passwords. <userinput>md5</userinput>

PAM profiles to enable: select all
</screen>

To configure the NSS module further, open
<filename>/etc/libnss-ldap.conf</filename>.
Locate and adjust the configuration lines as shown:

<screen>
base dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable>
uri ldap://<replaceable>192.168.7.12</replaceable>/
</screen>

Finally, to activate the LDAP NSS module, edit
<filename>/etc/nsswitch.conf</filename> by replacing the 
two lines mentioning <literal>passwd</literal> and 
<literal>group</literal> with the following:

<screen>
passwd:         files ldap
group:          files ldap
</screen>

<application>Nscd</application> (the Name Service Caching Daemon) is used
to cache metadata locally, instead of
querying the LDAP server each time. It is a very efficient service in the long
run, but we will stop it for for the moment, during testing, to always retrieve
the data directly from the LDAP server:

<programlisting>
sudo invoke-rc.d nscd stop
</programlisting>

Now we can verify that LDAP users have become visible:

<screen>
<userinput>id <replaceable>mirko</replaceable></userinput>

uid=<replaceable>20000</replaceable>(<replaceable>mirko</replaceable>) gid=<replaceable>20000</replaceable>(<replaceable>mirko</replaceable>) groups=<replaceable>20000</replaceable>(<replaceable>mirko</replaceable>)
</screen>

</para>
</section>

<section id="PAM_configuration"><title>PAM configuration</title><para>

The final step in this article pertains to integrating LDAP into
the system authentication procedure.
</para><para>
Let's install and configure <application>libpam-ldap</application>.
(You might have already done this step automatically, during
<application>libnss-ldap</application> installation &mdash; in that
case Debian will just report the package is already installed).
<programlisting>
sudo apt-get install libpam-ldap
</programlisting>

Debconf answers for reference:

<screen>
Make local root Database admin. <userinput>No</userinput>

Does the LDAP database require login? <userinput>No</userinput>

Local crypt to use when changing passwords. <userinput>md5</userinput>
</screen>

To configure the PAM module, open <filename>/etc/pam_ldap.conf</filename>.
Locate and adjust the configuration lines as shown:

<screen>
base dc=<replaceable>spinlock</replaceable>,dc=<replaceable>hr</replaceable>
uri ldap://<replaceable>192.168.7.12</replaceable>/
</screen>

Now let's configure &PAM; itself. PAM configuration is quite fragile, so use
the provided examples that have been verified to work. For any modifications,
you will want to look at &PSY; and pay special attention to seemingly
insignificant variations &mdash; with PAM, they often make a whole world of
difference.
</para>
<para>
PAM will require the user to be present 
<emphasis>either</emphasis> in the local password file
<emphasis>or</emphasis> in LDAP and to know the correct password,
for the authentication process to continue.
</para><para>
Note that authentication through LDAP, as shown here, is not secure,
due to connections to the LDAP server being made in plain text
and passwords travelling over the wire.
</para><para>
Instead of encrypting the connection to the LDAP server, the PAM files
shown below also support Kerberos for authentication, if you've 
installed Kerberos as explained in &DKLAR_KRB;. In that case, modify
the PAM lines as noted in file comments and the authentication will be
performed in a completely secure and superior manner using Kerberos.
</para>

<section><title>/etc/pam.d/common-account</title><para>
<screen>
account sufficient      pam_unix.so
account required        pam_ldap.so

# Enable if using Kerberos:
#account required        pam_krb5.so
</screen>
</para></section>

<section><title>/etc/pam.d/common-auth</title><para>
<screen>
# Disable the three lines if using Kerberos:
auth [success=1 default=ignore] pam_unix.so nullok_secure
auth required pam_ldap.so use_first_pass
auth required pam_permit.so

# Enable the three lines if using Kerberos:
#auth    sufficient        pam_unix.so nullok_secure
#auth    sufficient        pam_krb5.so use_first_pass
#auth    required          pam_deny.so
</screen>
</para></section>

<section><title>/etc/pam.d/common-password</title><para>
<screen>
password sufficient   pam_unix.so nullok obscure md5

# Disable if using Kerberos:
password required     pam_ldap.so use_first_pass 

# Enable if using Kerberos:
#password required pam_krb5.so use_first_pass
</screen>
</para></section>

<section><title>/etc/pam.d/common-session</title><para>
<screen>
session required        pam_unix.so
session required        pam_mkhomedir.so skel=/etc/skel/ umask=0022

# Enable if using Kerberos:
#session  optional  pam_krb5.so minimum_uid=1000
</screen>
</para></section>
</section>

<section>
<title>Logging in into the system</title>
<para>
Having everything adjusted as shown, login to the system should succeed
as user <literal><replaceable>mirko</replaceable></literal>:
<screen>
Login: <userinput><replaceable>mirko</replaceable></userinput>
Password: <userinput><replaceable>PASSWORD</replaceable></userinput>

Debian GNU/Linux tty5

Creating directory '/home/<replaceable>mirko</replaceable>'.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
<replaceable>mirko</replaceable>@host:~$

</screen>
</para>
</section>
</section>

<section>
<title>Conclusion</title>

<para>
DONATE_LINK
</para>

<para>
At this point, you have a functional LDAP installation.
</para><para>
You can rely on LDAP for central network authentication and sharing of 
user metadata (user IDs, group IDs, real names, group memberships, etc.). 
</para><para>
However, as said above, the authentication through LDAP is not done in
a network-secure manner, due to plain text connections and passwords travelling
over the wire. To solve that problem, using Kerberos for network authentication 
instead of LDAP is recommended, as explained in the previous article in the
series, the &DKLAR_KRB;.
</para><para>
Also, when users authenticate successfully, they will be logged in and placed
in their home directory. However, in a central network authentication scheme,
where users are not created on individual machines, their corresponding home
directories will not exist. This problem is taken care of by the
<literal>pam_mkhomedir</literal> module above, which automatically
creates missing home directories.
</para><para>
This means users' home directories will be created separately on all 
of the machines they log in. This may present a problem as people will
have different files on different machines. It won't be completely
unacceptable in itself if Kerberos is used, as the Kerberized network will
allow secure and passwordless copying of files between the machines, but it
will still be far from a perfect solution.  To solve that problem with an
advanced, secure, heavy-duty distributed network filesystem, see the
next article in the series, the &DKLAR_AFS;.
</para>

<para>
<emphasis role='bold'>With a good foundation we've built, for further
information on LDAP, please refer to other available resources:</emphasis>

<itemizedlist>
	<listitem><para>
	Official documentation: &DOC;
	</para></listitem>
	<listitem><para>
	Mailing lists: &MLS;
	</para></listitem>
	<listitem><para>
	IRC: channel #ldap at the FreeNode network (irc.freenode.net)
	</para></listitem>
</itemizedlist>
</para>
<para>
For commercial consultation and infrastructure-based networks containing
AFS, contact &SL; or organizations listed on the
<ulink url="http://www.openldap.org/support/">OpenLDAP support page</ulink>.
</para>
</section>

<section>
<title>Links</title>

<para>
Platforms:<sbr/>
	&GNU;                              <sbr/>
	&DEB;                              <sbr/><sbr/>

LDAP:<sbr/>
	&LDA;                              <sbr/>
	&GQCL; &mdash; Gtk LDAP Client     <sbr/>
	&LUMA; &mdash; QT LDAP Client      <sbr/>
	&JXPL; &mdash; Java LDAP Client    <sbr/>
	&ADSS; &mdash; Eclipse-based LDAP Client<sbr/>
	&W2LD; &mdash; web-based LDAP Client<sbr/><sbr/>

Glue layer:<sbr/>
	&NSS;                              <sbr/>
	&PAM;                              <sbr/><sbr/>

Related infrastructural technologies:<sbr/>
	&KRB;                              <sbr/>
	&AFS;                              <sbr/>
	&RAD;                              <sbr/><sbr/>

Commercial support:<sbr/>
	&SL;                               <sbr/>
	<ulink url="http://openldap.org/support/">OpenLDAP support organizations</ulink><sbr/><sbr/>

Misc:<sbr/>
	&DOCBK;                            <sbr/>
</para>
</section>

</article>

