/ Markus Amersdorfer:home / university / about:me /
\ capsaicin - my blog on growing chilis \


Part I: Using OpenLDAP on Debian Woody to serve Linux and Samba Users

Note on Debian Sarge:
Please check out Part II: OpenLDAP on Debian Pre-Sarge below for some information on LDAP with a pre-release version of Debian 3.1, aka "Debian Sarge".

Table of Contents

For Debian 3.0 aka Debian Woody:

For Debian 3.1 aka Debian Sarge pre-release version:

Part III was created for miscellaneous comments and addons added after the actual lifetime of this document and which are not exactly bug fixes of existing content:

User Comments:

Introduction

LDAP is one hell of a tool: it can be used to store any kind of information, starting with your network's users (which is what we'll do) and not even ending with your favorite cooking recipes.
As LDAP is one hell of a tool, it is all a pain in the you-know-what-I-mean to get to know it and to get it up and running. I spent lots of time with basics just to understand it. One problem for me was, that I didn't find any good documentation on this topic for a long time.
Anyway, here is first of all a small list of IMHO good documentation on this topic as well as my stuff to get it working: OpenLDAP (the software written to host the database and do some other stuff) implements one part of the whole LDAP-specification, AFAICT. We'll use it to do the major work: host the database. This "LDAP-server" (ldap.subnet.at) will serve to Linux and Windows workstations hosting the local users and corresponding information. Later on, it shall also serve the upcoming new Linux-based mailserver.

As Debian GNU/Linux is our distribution of choice, I'll focus on the description for Debian Woody. Nevertheless, lot's of stuff is generic material and you should be able to use it on other distributions too.

I'd like to thank all people I know and those I don't know which made this LDAP solution possible - just to mention a few groups: Debian, OpenLDAP, Samba, #ldap (irc.debian.org), the authors of all these Howto's and other documentations, package maintainers, etc. etc. etc.
Thanks!

This document was created during my work as network admin at subnet - platform for media art and experimental technologies.
This document's home is http://homex.subnet.at/~max/ldap/.

PDF version of this document

As Postscript- or PDF-versions of this document have been requested several times: I created this file's HTML/PHP code directly using vim -- which makes it a bit harder to create a proper PDF document that's up to date.
(If only I knew that this document became this large -- I'd really spent the time to learn DocBook first, or had used LyX -- or whatever.)

Still, Andreas Heinzen pointed out to me, how to easily create a PDF version of this document (the latest version is as of June 11, 2005). Many thanks again to Andreas for his work and feedback on this!
(Just to let you know - in case you want to do this yourself: Use html2ps and ps2pdf to create the document. Beforehand, the feedback-form and the counter should be removed from the source code.)

Document History

Security Advisory

I wouldn't have thought it to be necessary with a HOWTO, but it is: This section is for security issues coming up.

03-08-18

Overview:
The self-compiled Samba packages (DSA-280-1 samba -- buffer overflow) as well as the self-compiled LDAP packages (DSA-227-1 openldap2 -- buffer overflows and other bugs) used in previous versions of this HOWTO unfortunately are based on vulnerable versions of those packages. If you've simply downloaded and used the packages from this site, you are strongly encouraged to either recompile them yourself or use the new upgraded packages provided here.

Description:
For some reason I did not include "deb-src http://security.debian.org woody/updates main contrib non-free" in my /etc/apt/sources.list file when initially downloading and compiling the source packages, this means I used Woody's original packages which meanwhile turned out to be vulnerable here and there.)

Mind:
As to my knowledge, packages can now be considered "secure" currently. Nevertheless, Today's security advisory does not mean I necessarily put possibly needed packages up here in the future as well. Don't rely on this howto, keep track of security issues yourself!

04-03-25

There is a local root exploit in Samba 2.2.3a-12 that is fixed in Woody's 2.2.3a-13 packages (check out DSA-463).
04-09-02: Recompiled packages based on the fixed version 2.2.3a-13 are provided below now.

04-12-22

Samba 2.2.3a-13 is vulnerable, see DSA-600.
I removed the compiled packages, please follow the instructions below to build them yourself.

Licensing

This document is published under the licenses GPL and GFDL (see notes below for details). You may choose, which license to apply.

Copyright

Copyright © Markus Amersdorfer, subnet.

GNU Free Documentation License (GFDL)

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A current copy of the license should be available here. In case of failure, Version 1.2 of the GNU FDL is also available locally.

GNU General Public License (GPL)

This document may be used under the terms of the GNU General Public License version 2 or higher.
Permission is granted to make and distribute verbatim copies of this document provided the copyright notice and this permission notice are preserved on all copies.
Permission is granted to copy and distribute modified versions of this document under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.
Permission is granted to copy and distribute translations of this document into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the Free Software Foundation instead of in the original English.

Disclaimer

This document comes without any warranty and does not claim to be complete, nor does it necessarily hold correct information. The author(s) can not be held reliable for any loss of data or corrupted hardware or any other miscomfort due to information of this document. Use this at your own risk!

Original Author

Hosted by

External Resources

If you want to get to know what LDAP is and how its data is organized, please check out the docs in the following subsection "Learning about LDAP".

What Is LDAP?

I will not go into details, what LDAP really is and how to best design an LDAP tree - at least not for now. There are resources out there which can and do explain this, see section External Resources.

Nevertheless, I'd like to cite from the article Building an LDAP Server on Linux, Part 1 by Carla Schroder as she points out some IMHO crucial thing concerning the LDAP-world:
"Let's get like all pedantic for a moment (please put on your geek beard and pocket protector for this). LDAP--Lightweight Directory Access Protocol--is a protocol, not a database. It accesses a special kind of database that is optimized for fast reads. Use it for relatively static information, such as company directories, user data, customer data, passwords, and security keys. OpenLDAP uses the Sleepycat Berkeley DB. Having said all that, I'm not the pedant police; I'm OK with calling the whole works a database and being done with it."

Install OpenLDAP

First thing to do is to install the OpenLDAP-server.
I'd like to thank the author of the LDAP HOWTO over at howto.aphroland.de a lot. This doc helped me a lot by describing the installation from a Debian user's point of view. Lots of my description (above all to get this "LDAP-thing" do something close to what I wanted) is based on this doc and thus my howto cuts off some details which can be found at aphroland.de.
I'd like to notice one difference in advance: while aphroland's description uses a base structure like "o=domain,c=country" for the LDAP tree, I'll use the more common "dc=domain,dc=country". Nevertheless, this actually depends on your taste (among other things) and is just kind of a naming-convention.

We want our server (as well as the clients later on) to support SSL, so we'll have to recompile and install our own Debian packages:

Get the source:
  cd ~
  mkdir slapd_woody-source
  cd slapd_woody-source

  apt-get source slapd
  apt-get build-dep slapd
  apt-get install libssl-dev

Activate SSL:
  cd openldap2-2.0.23
  vi debian/rules
    --> and replace --without-tls with --with-tls
  [ vi debian/changelog ]

Compile the packages:
  dpkg-buildpackage -b -us -uc
FYI: "slapd" is the part of OpenLDAP which "is the server". With LDAP it is possible to reproduce the available database to other servers on the network too, which you'd use "slurpd" for (which we won't do).
Mind:
The packages provided on this page have an edited debian/changelog as well to hold information about what was changed: Additionally to mentioning the addition of SSL support here, the package names are changed to contain the suffix "subnet". (BTW: Run date -R to get the correct date string for the changelog.)
Note:
In previous versions of this document I stated to run ./debian/rules binary to compile the Deb packages. While this works, the somewhat more official way seems to me to be using dpkg-buildpackage instead.
(If for some reason the file debian/rules should not be executable, run chmod +x debian/rules.)

Invoking dpkg-buildpackage -b -us -uc creates the .deb-packages in ~/slapd_woody-source/, which you should install blindly accepting the default-values presented by Debconf. (As described at aphroland.de, we'll wipe out the default-stuff and start from scratch on ourselves.)

  cd ~/slapd_woody-source/
  dpkg -i slapd_2.0.23-6_i386.deb
          libldap2_2.0.23-6_i386.deb
	  libldap2-dev_2.0.23-6_i386.deb
	  ldap-utils_2.0.23-6_i386.deb
  [ Get subnet's self-compiled slapd packages ]
  /etc/init.d/slapd stop

In order to prevent the packages to be replaced by the ones from the Debian-repository, set them to HOLD. (Use dselect or a command like "echo "slapd hold" | dpkg --set-selections" for this.)
But be aware to keep track of possible security-updates for these packages on your own from now on! (Upgrading to the possibly new packages then should be easily possible by running "dpkg -i ..." again. Make sure to have backups of your configuration before as well as to set the packages to HOLD afterwards again.)

Configure OpenLDAP

Wiping out Debian's default configuration and setting up our own one works as follows:

  adduser slapd

  chown -R slapd.slapd /etc/ldap
  chmod 770 /etc/ldap
  find /etc/ldap -type f -exec chmod 440 {} \;
  find /etc/ldap -type d -exec chmod 770 {} \;
  chown -R slapd.slapd /var/lib/ldap
  chmod 750 /var/lib/ldap
  rm /var/lib/ldap/*
  chown -R slapd.slapd /var/spool/slurpd
  rm /var/spool/slurpd/*
                                                                                                   
  cd /etc/ldap/
  mv slapd.conf slapd.conf_DEB-orig

This way, the user "slapd" (which we'll use to run the LDAP-server later-on) is the only one who can read the LDAP configuration as well as the database.

Here's the first basic version of our main configuration file, /etc/ldap/slapd.conf:

######################### /etc/ldap/slapd.conf #########################
# http://homex.subnet.at/~max/ldap/
# 
# Basic slapd.conf

include         /etc/ldap/schema/core.schema
include         /etc/ldap/schema/cosine.schema
include         /etc/ldap/schema/nis.schema
include         /etc/ldap/schema/inetorgperson.schema
include         /etc/ldap/schema/misc.schema

schemacheck     on
pidfile         /home_local/slapd/slapd.pid
argsfile        /home_local/slapd/slapd.args
password-hash   {CRYPT}
replogfile      /var/lib/ldap/replog
loglevel        256
database        ldbm

suffix          "dc=subnet,dc=at"
# use "/usr/sbin/slappasswd -h {CRYPT}" to create a rootpw-string below
# (note: if you use the tcsh shell, you will have to use single quotes
#        to surround the {CRYPT}, i.e.: /usr/sbin/slappasswd -h '{CRYPT}')
rootpw          {CRYPT}xxxxxxxxxx
directory       "/var/lib/ldap"
index objectClass eq
lastmod         on

access to attribute=userPassword
        by dn="cn=manager,dc=subnet,dc=at" write
        by anonymous auth
        by * none
                                                                                                   
access to *
        by dn="cn=manager,dc=subnet,dc=at" write
        by dn="cn=nss,dc=subnet,dc=at" read
        by * auth
#######################################################################

Differences to aphroland's description include using {CRYPT}-hashes instead of {MD5}-ones as well as starting the server as root and have it drop his privileges in order to become the user "slapd" as soon as it has bound to the ports 389 and 636. (See below for details.)

Next, besides editing the rootpw-line in your slapd.conf, run some more file-system stuff:

  # chown slapd.slapd slapd.conf
  # chmod 440 slapd.conf

  # ll
  total 12
  drwxrwx---    2 slapd    slapd        4096 Jun  3 14:38 schema
  -r--r-----    1 slapd    slapd         864 Jun  3 14:41 slapd.conf
  -r--r-----    1 slapd    slapd        1928 Jun  3 14:38 slapd.conf_DEB-orig

Database Population

As our database is currently less than empty, we need to populate it.
To be able to test the setup, use a file like the following which holds the basic data to be added. As you've already checked out some general documents on LDAP (haven't you?), you should already know that this file is in "LDIF"-format:

dn: dc=subnet,dc=at
objectClass: organization
o: subnet

dn: cn=manager, dc=subnet,dc=at
objectClass: organizationalRole
objectClass: simpleSecurityObject
cn: admin
description: LDAP administrator
userPassword: {CRYPT}xxxxxxxxxx

dn: cn=nss, dc=subnet,dc=at
objectClass: organizationalRole
objectClass: simpleSecurityObject
cn: nss
description: LDAP NSS user for user-lookups
userPassword: {CRYPT}xxxxxxxxxx

dn: ou=People, dc=subnet,dc=at
objectClass: organizationalUnit
ou: People

dn: ou=Group, dc=subnet,dc=at
objectclass: top
objectclass: organizationalUnit
ou: Group

dn: uid=maxldap, ou=People,dc=subnet,dc=at
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
objectClass: organizationalPerson
objectClass: inetLocalMailRecipient
uid: maxldap
cn: Markus LDAP Test User Amersdorfer
sn: Amersdorfer
givenname: Markus LDAP Test User
title: Admin
departmentNumber: IT
mobile: 012-345-6789
postalAddress: AddressLine1$AddressLine2$AddressLine3
telephoneNumber: 1234-567890
facsimileTelephoneNumber: 012-345-6789
userpassword: {CRYPT}xxxxxxxxxx
labeleduri: http://homex.subnet.at/~max/
mail: my.email.address@example.com
mail: my.alternate.email.address@example.com
mailRoutingAddress: my.email.account@mail.server.example.com
loginShell: /bin/bash
uidNumber: 12345
gidNumber: 12345
homeDirectory: /home_local/maxldap/
gecos: maxldap_gecos-field
description: Not Available
localityName: Bellevue

dn: cn=maxldap,ou=Group,dc=subnet,dc=at
objectClass: posixGroup
objectClass: top
cn: maxldap
gidNumber: 12345

Don't forget to run the "/usr/sbin/slappasswd -h {CRYPT}"-command to create password-hashes for the users with {CRYPT}-entries listed in the .ldif-file.
(Again, if you use the tcsh shell, this might produce an error stating something like "Password generation failed for scheme CRYPT: scheme not recognized". To work around this, surround the parameter with single quotes, i.e. run the following command instead: "/usr/sbin/slappasswd -h '{CRYPT}'". Also see this OpenLDAP mailing-list article on this issue.
Many thanks to Martin B. Smith for pointing this out!)

The normal user uid=maxldap:
Mind the naming pattern used here for the normal user "maxldap": its distinguished name "dn:" (which is unique within the global LDAP namespace) is constructed by using the user's "uid=maxldap" attribute (which equals to the Linux user's login name, the corresponding Linux user's UID can be found as LDAP's attribute "uidNumber") prefixing the tree "ou=People,dc=subnet,dc=at".
This places the user in the organizational unit "ou=People" of "subnet.at" ("dc=subnet,dc=at"). Some sites use the users' common names ("cn:") instead of the uid's to differentiate between single LDAP entries (users). While it basically boils down to a matter of taste on the one hand (whether you prefer "uid=maxldap,ou=People,..." over "cn=Markus Amersdorfer,ou=People,..." or the other way round), on the other hand it's definitely better to use "uid=" here. The simple reason is that both the MigrationTools (see section Migrate Your Linux Users below) and Samba (see section Samba 2.2.x and LDAP below) use this pattern. You'll save yourself a lot of time if you stick with "uid=,ou=,dc=,dc=".

The special user cn=nss:
With our current ACLs, nobody except cn=manager and cn=nss can perform standard read functionality on our LDAP tree. Nevertheless, to be able to become a user (e.g. using "su user") or to get information about the user ("finger user"), the tree must be readable, at least to the Name Switch Service (NSS) (see section NSS: Name Service Switch below).
It depends on your situation to either set read-rights for everyone to ou=People, or to use this cn=nss user so that NSS can lookup the users. I'll describe the latter scenario.

You can and should add the data above to the (currently not running) OpenLDAP database by executing:

  # su - slapd
  $ /usr/sbin/slapadd -l /etc/ldap/basics-subnet.ldif

Using "slapcat" you get the database's current contents without having to perform "ldapsearch" or similar. This can be useful for debugging processes.

Start OpenLDAP

You can now - being root - start the OpenLDAP server (without having it disappear into daemon-mode):

  # /usr/sbin/slapd -u slapd -h ldap://0.0.0.0/ -d 255

This starts the OpenLDAP server "slapd" initially as root, binds to the corresponding port (TCP/389) on all local interfaces, drops root privileges by becoming the user "slapd" and presents you with 'live' debugging information on your screen.
(Hint: Browse through this stuff to get a feeling for OpenLDAPs debugging information and error messages.)

Having the OpenLDAP server up and running, we can deal with the client-side now...

NSS: Name Service Switch

NSS: Introduction

On Linux (and some other UNIX-flavours), accessing the users-database is not just looking up the passwd/shadow/a.s.o. files. Nowadays, most applications use library calls to get user information or accomplish user authentication.
While the PAM system (Pluggable Authentication Module, see below) is used to accomplish a user's authentication (i.e. checking if provided login and password are correct, accomplish some other (stackable and thus highly configurable) tasks and finally decide for example whether the user may login or not), the Name Service Switch is a service which provides you with a user/group/a.s.o. listing. To get your local machine's or network's listing, just run "getent passwd".

The first task now is to set up the NSS correctly to query the OpenLDAP server additionally to the local passwd-files (and/or the already used NIS). This is done by installing the package "libnss-ldap" and configuring the nss-processes to use it.

This description goes for both your network-clients as well as the LDAP-server itself (as we want the server's Linux-system too to know the users and other information stored using OpenLDAP)!

NSS: Installation (with SSL capable packages)

In order to have any traffic between the clients and server be encrypted, we again need to compile the packages ourselves to support SSL. (The actual configuration of encrypted communication can be found later in the document.)

  cd ~
  mkdir libnss-ldap_woody-source
  cd libnss-ldap_woody-source

  apt-get source libnss-ldap
  cd libnss-ldap-186
  vi debian/rules
    --> and replace --disable-ssl with --enable-ssl
  [ vi debian/changelog ]

  dpkg-buildpackage -b -us -uc

  dpkg -i libnss-ldap_186-1_i386.deb
  [ Get subnet's self-compiled libnss-ldap package ]
  echo "libnss-ldap hold" | dpkg --set-selections

  mv /etc/libnss-ldap.conf /etc/libnss-ldap.conf_DEB-orig

The final two commands install the new libnss-ldap-package and set it to HOLD status.
But be aware to keep track of possible security-updates for these packages on your own from now on! (Upgrading to the possibly new packages then should be easily possible by running "dpkg -i ..." again. Make sure to have backups of your configuration before as well as to set the packages to HOLD afterwards again.)

Mind: The manual page for libnss-ldap.conf does not specify all of the module's options. In order to be able to browse through the capabilites later (and perhaps activate some of them), we made a backup of Debian's original and (throughout the file itself) well-documented libnss-ldap.conf-file.

Once the package is installed, use the following /etc/libnss-ldap.conf file to configure the new functionality correctly:

######################### /etc/libnss-ldap.conf ########################
# http://homex.subnet.at/~max/ldap/

host ldap.subnet.at
base ou=People,dc=subnet,dc=at
uri ldap://ldap.subnet.at/
ldap_version 3

binddn cn=nss,dc=subnet,dc=at
bindpw the_one_you_set_above_in_the_ldif-file__as-plaintext

nss_base_passwd ou=People,dc=subnet,dc=at
nss_base_group  ou=Group,dc=subnet,dc=at
#######################################################################

The bindpw-entry is the password for the NSS-user (cn=nss,dc=subnet,dc=at) you created above when populating the LDAP database. The password has to be stated as plaintext here, do not use the {CRYPT}-hash.

Now, include the LDAP NSS module in the system lookups by editing /etc/nsswitch.conf:

  passwd:         ldap compat
  group:          ldap compat
  shadow:         ldap compat

This way, lookups for passwd, group and shadow try LDAP first ("ldap") and NIS and the local files next ("compat").
(If a user is listed both locally and in LDAP, it will also show up twice in the output. This feature is used in the setup described here to have the user "root" both be served from LDAP and - as a fallback in case of LDAP wasn't reachable - have it stored locally. See section PAM: The user "root" and other system UIDs below for details.)

It should be possible to lookup the LDAP-user "maxldap" using finger or getent now:

  # finger maxldap
  Login: maxldap                                Name: maxldap_gecos-field
  Directory: /home_local/maxldap/       Shell: /bin/bash
  Last login Mon Jun  2 16:53 (CEST) on pts/1 from some-client.subnet.at
  No mail.
  No Plan.

NSCD and /etc/libnss-ldap.conf

NSCD is "a daemon which handles passwd, group and host lookups for running programs and caches the results for the next query". While this makes NSS-lookups faster, it also might lead to the situation where it might take some time for an update of user-data to reach all clients. (Or is there some "pushing"- or any other mechanism that solves this?)

Anyway, installing "nscd" might definitely be a good idea from the security point of view: The above mentioned /etc/libnss-ldap.conf file holds some clear-text information necessary to be able to perform NSS-lookups. In order to prevent the users from not knowing who they are - resulting in funny situations such as the prompt saying "i have no name!" instead of the actual user's login-name - this file has to be world-readable. But then, this means that everybody knows about the credentials of the "cn=nss" user and can do everything this special user can (which depends on the access-lists of the LDAP server).

Though I haven't tried it yet, NSCD can help you solve this issue: Just install it and set the file-access-rights for /etc/libnss-ldap.conf to "600" (owned by root).
In this setup, the corresponding library-request executed with the user's rights should be handled by NSCD, which in turn runs with root-privileges (I guess, at least), and thus can read the credentials from the config-file and perform the corresponding DB-lookup.

PAM: Pluggable Authentication Module

PAM: Introduction

As mentioned above, user lookups are seperated from user authentication on Linux systems. While the first is covered by NSS, the second is usually dealt with using PAM nowadays.

Basically, it's the same process here for the package "libpam-ldap" as it was with libnss-ldap above: recompilation with SSL enabled and installation of the new package.
Nevertheless, the Debian Woody package has a special patch applied to be able to use filters when checking whether a user is allowed to login or not. We'll use this feature to be able to allow users to login to some specific workstations and block access on the network's other workstations (see below for details).
Unfortunately, this filter patch has a bug, which means we'll need to install a patched version of libpam-ldap, compiled ourselves to support SSL. This patched version is available from Christof Meerwalds Debian section.

PAM: Clients vs. Server Configuration

As with NSS, we want the LDAP-server itself too to be able to use the LDAP-based users for authentication. Thus, basically, the same configuration applies to the server as it does to the client machines (= Linux/Unix stations not running the LDAP server but just querying it for user lookups and authentication.)

Nevertheless, you have several options here now, depending on your needs and wishes. It's all about the user "root" and about changing user passwords.

  1. You can configure a machine so that there is no almighty root anymore concerning the users. If you do so, root can not add users - root can't even change the users' passwords. This can be bad (additional "overhead", necessary change of habits) or good (the system administrator "root" is not responsible/able to change the users' passwords, this can/must be done by someone else) - depending on your needs. You can keep the system-administrator (responsible for a machine's uptime) seperated from the users administration. (This is not totally correct: root can change a user's password, but it has to know the user's old password to able to set a new one. This is the same behaviour as if the users theirselves would change their passwords.)
  2. You can configure a machine to behave as if users were "installed" locally (in passwd|shadow) so that root can change them and their passwords.

I'll describe a setup here where root can change any user's password, but only on the machine running the OpenLDAP server. Reasons are that I want root to be able to change the passwords by simply running "passwd $user" (without having to know the user's old password). Nevertheless, this ability includes the need for the password for "cn=manager,dc=,dc=" to be stored on such a machine locally in a file, additionally it has to be in plaintext. This doesn't seem to be easy to administer (especially in the case where the manager's password changes) on the one hand, and it doesn't seem to be very secure either for obvious reasons on the other hand.

The only difference lies in the file "/etc/pam_ldap.conf" using the option "rootbinddn" on the server and "binddn" on all other machines. Furthermore, the server needs the file "/etc/ldap.secret" which holds the manager-user's password in plaintext (with access rights "600", owned by "root").

Most of the steps following are the same for all machines, no matter which configuration you chose. If not stated otherwise, it's the same for both possible setups.

PAM: Installation (with SSL capable packages)

Add to /etc/apt/sources.list:
  # Patched libpam-ldap for Woody (http://cmeerw.org/debian/)
  deb-src http://cmeerw.org/files/debian woody libpam-ldap

Run:
  cd ~
  mkdir libpam-ldap_cmeerw-source
  cd libpam-ldap_cmeerw-source

  apt-get update
  apt-get source libpam-ldap

  vi debian/rules
    --> and replace --disable-ssl with --enable-ssl
  [ vi debian/changelog ]

  dpkg-buildpackage -b -us -uc

  cd ..
  dpkg -i libpam-ldap_140-1cmeerw_i386.deb
  [ Get subnet's self-compiled libpam-ldap package ]
  echo "libpam-ldap hold" | dpkg --set-selections

  mv /etc/pam_ldap.conf /etc/pam_ldap.conf_DEB-orig

Again after installing the package, we set its status to HOLD.
But be aware to keep track of possible security-updates for these packages on your own from now on! (Upgrading to the possibly new packages then should be easily possible by running "dpkg -i ..." again. Make sure to have backups of your configuration before as well as to set the packages to HOLD afterwards again.)

Though we'll use a setup without SSL and without host-specific access controls for the moment, using the patched package and recompiling it with our modifications we're ready for these things to come later on.
Mind: The manual page for pam_ldap.conf does not specify all of the module's options. In order to be able to browse through the capabilites later (and perhaps activate some of them), we made a backup of Debian's original and (throughout the file itself) well-documented pam_ldap.conf-file.

Next, on all the clients (where root is not able to change the users' passwords), configure the new PAM module using this /etc/pam_ldap.conf:

########################## /etc/pam_ldap.conf #########################
# http://homex.subnet.at/~max/ldap/
#
# pam_ldap.conf for all client machines

host ldap.subnet.at
base dc=subnet,dc=at
uri ldap://ldap.subnet.at/
ldap_version 3

binddn cn=nss,dc=subnet,dc=at
bindpw the_one_you_set_above_in_the_ldif-file__as-plaintext

pam_password crypt
#######################################################################

On the server (or on all machines where you want root to be able to change the users' passwords), first, use this /etc/pam_ldap.conf:

########################## /etc/pam_ldap.conf #########################
# http://homex.subnet.at/~max/ldap/
#
# pam_ldap.conf for the server (where root can change user passwords)

host ldap.subnet.at
base dc=subnet,dc=at
uri ldap://ldap.subnet.at/
ldap_version 3

rootbinddn cn=manager,dc=subnet,dc=at
# don't forget /etc/ldap.secret

pam_password crypt
#######################################################################

and second don't forget to create the file /etc/ldap.secret with access rights "600" and owned by "root" (i.e. only root can read the file) which holds the plaintext-password for LDAP's "cn=manager,...".
(While, if I'm correct, I didn't have such in my setup originally: according to Setting up LDAP for use with Samba, there has to be a blank second line in this file.)

Now that we have the PAM module configured, we need to include it into the PAM process: We'll check out the modifications to be able to log in using ssh and su.
Most PAM-aware applications have their own PAM-stack they use. Debian stores these configuration-files in /etc/pam.d/.
Here is /etc/pam.d/ssh:

########################### /etc/pam.d/ssh ############################
# http://homex.subnet.at/~max/ldap/

auth       required     pam_env.so
# Woody's SSHD checks for /etc/nologin automatically,
# so there's no need for pam_nologin in /etc/pam.d/ssh.
#auth       required     pam_nologin.so
auth       sufficient   pam_ldap.so
auth       required     pam_unix.so
 
account    sufficient   pam_ldap.so
account    required     pam_unix.so
 
session    sufficient   pam_ldap.so
session    required     pam_unix.so
session    optional     pam_lastlog.so # [1]
session    optional     pam_motd.so # [1]
session    optional     pam_mail.so standard noenv # [1]
session    required     pam_limits.so

password   sufficient   pam_ldap.so
password   required     pam_unix.so
#######################################################################

The changes to the original file are:

Here is /etc/pam.d/su as another example:

########################### /etc/pam.d/su #############################
# http://homex.subnet.at/~max/ldap/

auth       sufficient pam_rootok.so
auth       sufficient pam_ldap.so
auth       required   pam_unix.so use_first_pass

account    sufficient pam_ldap.so
account    required   pam_unix.so

session    sufficient pam_ldap.so
session    required   pam_unix.so
#######################################################################

The changes to the original file are:

Things to take care of:

Logging in via SSH or su'ing to the LDAP-user "maxldap" should work now:

  $ ssh maxldap@ldap.subnet.at
  maxldap@ldap.subnet.at's password:
  Last login: Tue Jun  3 15:11:30 2003 from some-client
  maxldap@ldap:~$

PAM: Passwords: Facts

CRYPT vs. MD5:
The good old shadow file typically stores passwords as hashes using the "crypt" algorithm. More up to date systems often use "md5" somewhere in the process of hashing the password. (These "md5"-passwords can be distinguished from the "crypt"-only ones by starting with "$1$".)
The Mandrake-based document on mandrakesecure.net (see section External Resources) describes a way to use exactly the newer MD5-based approach with your LDAP database. Unfortunately, either Debian doesn't support it or I simply couldn't get this thing to work. (It seems I managed to have passwords being created using MD5 and have them stored in the LDAP database this way, but unfortunately, I couldn't use these hashes. I never got a user to authenticate successfully.) Being well known for my paranoia ;), I really would have liked the MD5-thing as it creates longer password hashes and uses passwords with more than just 8 characters. Anyway, good old CRYPT will (have to) suffice...

BTW: One reason for even me thinking that "crypt" really is secure enough is that the password is never sent in any way in plaintext over the network, as every traffic between clients and server is secured using SSL (see below). Even a local "root" user can't see the password-hash by executing "getent shadow". Only the "LDAP Manager" is allowed to see the hash.
The only (really bad) thing you should remember is: "Crypt"-passwords have a maximum length of 8 characters!

PAM: Passwords: How To Change Them

Here is my /etc/pam.d/passwd. Using it, the users can change their passwords on their own from the command-line by simply executing passwd.

########################### /etc/pam.d/passwd ###########################
# http://homex.subnet.at/~max/ldap/

password        sufficient      pam_ldap.so
password        required        pam_unix.so nullok obscure min=4 max=8
#########################################################################

I tried several versions here. Unfortunately, this is the only one I found where both root and the users themselves (both LDAP-based users and local-only ones in passwd|shadow) can change their passwords.
(Especially, I could not get the stuff working using pam_cracklib.so or using use_first_pass with pam_unix.so. This would have been nice!)

Oh, and of course, don't forget the setup of /etc/pam_ldap.conf concerning root's non/ability to change users' passwords explained in section PAM Clients vs. Server Configuration above, but you've already read it anyway, haven't you?

PAM: The user "root" and other system UIDs

(You actually don't have to worry about that just yet, just bare in mind you will have to decide later (when actually doing all the migration stuff in section Migrate Your Linux Users below) what to do with all the system accounts and with "root". Nevertheless, as it's about user accounts, I think the general knowledge about it belongs to PAM and thus here.)

I definitly recommend to keep your system UIDs (Debian currently treats the UIDs 1-999 as such) only locally on every machine, do not migrate them into LDAP!
It's up to you what you do with "root". If you prefer to have one root account for all machines (as I do), migrate "root" to LDAP. Otherwise, just treat it as a system account and do not migrate it.

The system UIDs

If you need reasons for not migrating them to LDAP:
Different services on different servers/machines will need different system users to be present (e.g. the user "mysql" should only be available on a machine hosting a MySQL server).
One day, you will upgrade your machines from Woody to Sarge. It can (and probably will) happen that according to a new policy some system accounts changed their UID. Upgrading just only one server will not work in this context, as the user "root" should not be able to simply change those LDAP values. Even if it worked properly for one server, what about the second? (Well, ok, everything might turn out to work somehow, but IMHO you really don't want it this way :) ...)
And of course (above all), if you want to serve your users to client machines which do not run Debian Woody and thus use a different system accounts scheme, you'll have problems on your hands.

UID 0: "root"

If you want to migrate the user "root" into LDAP (like I did), simply migrate it as described below in section Migrate Your Linux Users.

But be sure to also have "root" locally in /etc/(passwd|shadow|group). If for some reason your LDAP server was not reachable, you still can log in to your (LDAP)-client machines using the local "root" account.
With the setup explained here, logging in as "root" will use the LDAP-account by default. Only if the LDAP server is not accessible, you will automatically fall back to the local user/password from the flat files. Try this yourself to make sure your machines behave properly. (Mind the order "ldap compat" in /etc/nsswitch.conf, described in section NSS: Installation (with SSL capable packages).)

ToDo - verify this again:
Oh, and before I forget and because it differs from standard Linux behaviour: if "root" tries to change its LDAP-account password using "passwd", it also needs to know its old password, just as any other user does!
(If you can't remember the password anymore, you'll need to change it directly in the LDAP database, but that's probably what you will do anyway, won't you? :) ...)
Additionally, this also depends on section PAM Clients vs. Server Configuration, actually...

Host Specific Access

Introduction

Up to now, if a user shall has access to one host, they actually have access to all hosts on the network.

As described in the Mandrake based LDAP-article already mentioned in the resources section, one can define one or more "host"-attributes (host is part of "objectClass: account") in the user's LDAP-entry, specifying that this user is allowed to login to the listed host(s).
Debian offers several ways to achieve our goal, from "simple" to "advanced":

Approach 1: pam_check_host_attr

For every host the user shall be able to login, add an attribute similar to "host: allowed-host.mydomain.net".

While Mandrake seems to have merged "libnss-ldap.conf" and "pam_ldap.conf" to on single "ldap.conf" file, you already know that Debian uses the split-up approach.
The "pam_check_host_attr" option can be found in "/etc/pam_ldap.conf", you can add the following there:

/etc/pam_ldap.conf
  [...]
  pam_check_host_attr yes

But be careful: As the comment in Debian's original pam_ldap.conf indicates, you'll need pam_ldap.so to be "configured for account management (authorization)". This means, that in the /etc/pam.d/<service> files, you'll have to replace "account sufficient pam_ldap.so" with "account required pam_ldap.so". (Otherwise, despite the message "Access denied..." the user will be granted access to the host.)

Approach 2: Filters

The more powerful way is the following one:
Debian's package libpam-ldap has a "filtering" patch applied. This way it is possible to accompany the LDAP PAM module with some filtering-rules which must match in order for the module to return successfully and allow the authentication-process to proceed.
As already mentioned in section PAM: Pluggable Authentication Module, the standard Woody package's filter patch has a bug which needs to be fixed. As we've installed the corrected version from cmeerw.org, we already have a working version.

So here's how to do it:
For every host that the user shall be able to login, add an attribute similar to "host: allowed-host.mydomain.net". If the user is allowed to login to all hosts, simply add "host: *" to the LDAP entry.
Next thing is to adapt the PAM stack: This can either be done by editing one (or more) specific service's config file in /etc/pam.d/, or by editing /etc/pam_ldap.conf (which has influence on all services at once):

For single services only (e.g. /etc/pam.d/ssh):
  #auth       sufficient   pam_ldap.so
  auth       sufficient   pam_ldap.so filter=|(host=this-host.mydomain.net)(host=\*)

For all services at once (/etc/pam_ldap.conf):
  pam_filter |(host=this-host.mydomain.net)(host=\*)

Only if the user's LDAP entry contains "host: this-host.mydomain.net" or "host: *", they are allowed to login.

Things to take care of:

Add-On:
Of course this setup can be extended for example by using self-defined attributes representing groups of hosts (e.g. "my-hosts: workstations") and adapting the PAM module's filters.
With a little imagination it could perhaps also be possible to assign a user different shells on different hosts!? I don't know yet...
It's all up to you. :)

SSL Encryption

Now that we have a running LDAP-server which provides user-information and also have clients authenticating using these LDAP-users, let's move on and make everything safer: Up to now, any traffic between the server and the clients was unencrypted. Let's activate the SSL-encryption our packages already are capable of (as we recompiled them ourselves).

You can find a description of how to create an SSL certificate here: HOWTO Create an SSL Certificate.

Once you have your signed certificate, you need to configure your OpenLDAP server to use it:

Add to your /etc/ldap/slapd.conf:
  [ ... loglevel xxx ]

  TLSCipherSuite HIGH:MEDIUM:+SSLv2
  TLSCertificateFile /etc/ldap/server.cert
  TLSCertificateKeyFile /etc/ldap/server.key
  TLSCACertificateFile /etc/ldap/ca.cert
  TLSVerifyClient 0

  [ ... database ldbm ]

Start the LDAP server with the following command:
  # /usr/sbin/slapd -u slapd -h 'ldap://0.0.0.0/ ldaps://0.0.0.0/' -d 1

You can test the server's SSL capabilities (of course the client you are executing the second command needs the "ldap-utils"-package with SSL-support compiled into it!):

  ldapsearch -b "ou=People,dc=subnet,dc=at" -LLL -D "cn=manager,dc=subnet,dc=at" \
    -H "ldap://ldap.subnet.at/" -W -x "(uid=maxldap)"
  ldapsearch -b "ou=People,dc=subnet,dc=at" -LLL -D "cn=manager,dc=subnet,dc=at" \
    -H "ldaps://ldap.subnet.at/" -W -x "(uid=maxldap)"

Both commands, with and without SSL encryption, should return the entry for the user "maxldap".

Activate SSL Encryption for the Clients' Queries

Next step is to adapt the clients' setup:
Having already installed our re-compiled library-packages, this is as easy as changing "uri ldap://ldap.subnet.at/" to "uri ldaps://ldap.subnet.at/"> in both /etc/libnss-ldap.conf and /etc/pam_ldap.conf.

Add-On:
To test if your clients really are communicating with the server using an encrypted connection, make user-queries and logins with both settings ldap:// and ldaps:// and a concurrently running "tcpdump -X host ldapserver". This tcpdump-command shows you in ASCII the transmitted data. While using ldap:// you should be able to find some cleartext in the data garbage, after switching to ldaps:// you should only see ... well, lot's of stuff, but no plaintext information.

OpenLDAP Startup Script

Now that we have everything set up correctly concerning the connections (including SSL-support), we should look at the changes necessary to /etc/init.d/slapd to have the OpenLDAP server started correctly every time the machine boots - all we have to do is to change one line:

  # start-stop-daemon --start --quiet --pidfile "$pf" --exec /usr/sbin/slapd
  start-stop-daemon --start --quiet --pidfile "$pf" --exec /usr/sbin/slapd -- -u slapd \
    -h 'ldap://0.0.0.0/ ldaps://0.0.0.0/'

This way, we have the process' user changed to "slapd" as well as the server listen for ldap-traffic on port 389 and ldaps-traffic on port 636.

"slapd" now logs to /var/log/debug.

So Far So Good, Part 1

So far, on the server side we have accomplished to set up and populate the OpenLDAP server.
Next, on the client side (this means every machine querying OpenLDAP, this most probably also includes the "server" where OpenLDAP is running on) we have configured the Linux clients to use it, they can look up the users and use those to log into machines. Communication between the clients and the server is secured using SSL encryption.
All you have to set up on each "client" is:

Migrate Your Linux Users

Migrate Linux: Prerequisites

Of course you want to migrate your current Linux users from passwd/shadow to the new OpenLDAP server. Debian offers help here by providing the MigrationTools from padl.com as the Debian package migrationtools, so you could apt-get install this package.
Unfortunately, the package in Debian Woody (version 40-1) is rather buggy: "migrate_base.pl" forgot an "s" with "dc: subnet", "migrate_group.pl" didn't produce any output and "migrate_passwd.pl" produced junk values for the attributes "cn", "givenname" an "sn". Furthermore, the latter also uses different letter cases in a newer version than Woody's one does (e.g. "givenName" instead of "givenname").
The newer version of Debian Sarge (currently version 44-6) definitely works better, but also still produces junk values for the attributes "cn".

In order to get a working package you should download the original version of the MigrationTools from padl.com. I used version 44, which works fine for me.

In either case, you'll have to execute the scripts on the machine which currently holds your users already, in my case this was our NIS server (which was a different machine than the upcoming LDAP server), so install the migration-package there.

After exploding the tar-ball, edit /usr/local/MigrationTools-44/migrate_common.ph and adapt the following variables:

  $DEFAULT_MAIL_DOMAIN = "subnet.at";
  $DEFAULT_BASE = "dc=subnet,dc=at";
  $DEFAULT_MAIL_HOST = "mail.subnet.at";
  $EXTENDED_SCHEMA = 1;

Citing the initial Mandrake-LDAP document on this one (with "localisation"): "This sets some defaults for the migrated data. Here we set the default mail domain, in this case "subnet.at" which will assign all users a default email address of "user@subnet.at". The default base is "dc=subnet,dc=at" which should be identical to the suffix defined in slapd.conf. The default mail host is the SMTP server used to send mail, in this case "mail.subnet.at". The extended schema is set to 1 to support more general object classes."

03-08-12:
As Buchan Milne pointed out in a mail on the Samba mailing-list and his Howto Implementing disconnected authentication and PDC/BDC relationships using Samba and OpenLDAP, changing those values in migrate_common.ph is not necessary: Setting and exporting according environment variables (for example export LDAP_DEFAULT_MAIL_DOMAIN="subnet.at") works too and would survive an eventual upgrade (though of course migrating users will probably be performed only once).

It's possible to migrate nearly all data to LDAP (including /etc/(hosts|protocols|services) etc.), nevertheless, the only things we'll use LDAP for are users and groups. ("hosts" would be good to migrate too, but we have a local DNS server running, so no need for this here.)
Furthermore, as already mentioned above in section PAM: The user "root" and other system UIDs, you'll have to exclude your system accounts (Debian Woody uses the UIDs 1-999 for this) and decide on what to do with "root" (UID 0). Especially keep in mind when migrating both groups and users to delete all system accounts from the .ldif-file created by the migration scripts!
ToDo: It should be possible to do this using some /sed/awk/grep/etc/ scripts.

Migrate Linux: The Scripts

The migration scripts are located in /usr/local/MigrationTools-44/ (or wherever you saved them to):
migrate_base.pl creates the LDAP tree's base structure.
The migrate_all_* migrate everything by simply calling the single perl scripts.
As I've already mentioned, the only things we'll migrate are users and groups, and of course we'll check out the base structure, so let's start with this one:

migrate_base.pl

  cd /usr/share/migrationtools/
  ./migrate_base.pl > base.ldif

The only entries which are or might become interesting for us are the following base.ldif:

dn: dc=subnet,dc=at
dc: subnet
objectClass: top
objectClass: domain
objectClass: domainRelatedObject
associatedDomain: subnet.at

dn: ou=People,dc=subnet,dc=at
ou: People
objectClass: top
objectClass: organizationalUnit
objectClass: domainRelatedObject
associatedDomain: subnet.at

dn: ou=Group,dc=subnet,dc=at
ou: Group
objectClass: top
objectClass: organizationalUnit
objectClass: domainRelatedObject
associatedDomain: subnet.at

(Here is the original base.ldif file with all the additional entries.)

Well, we basically do have this base structure already. The only difference is that we are missing "objectClass: domainRelatedObject" and its associated attribute.
So we won't do anything here at the moment.

migrate_group.pl

Here is the minimized output from ./migrate_group.pl /etc/group group.ldif:

dn: cn=max,ou=Group,dc=subnet,dc=at
objectClass: posixGroup
objectClass: top
cn: max
userPassword: {crypt}x
gidNumber: 1000

dn: cn=users,ou=Group,dc=subnet,dc=at
objectClass: posixGroup
objectClass: top
cn: users
userPassword: {crypt}x
gidNumber: 100

dn: cn=nogroup,ou=Group,dc=subnet,dc=at
objectClass: posixGroup
objectClass: top
cn: nogroup
userPassword: {crypt}x
gidNumber: 65534

This information can now be added to the LDAP server by executing something like the following:

  ldapadd -H ldap://ldap.subnet.at/ -D "cn=manager,dc=subnet,dc=at" -x -W -f $FILE

BTW: The main purpose of a group is to hold several users :).
An entry in /etc/group like "somegrp:x:12345:userone,usertwo" can be accomplished by adding a "memberUid" attribute for each user to the group's LDAP entry: "memberUid: userone" and "memberUid: usertwo".

migrate_passwd.pl

  ./migrate_passwd.pl /etc/passwd passwd.ldif

  # Restrict access as this file holds all passwords:
  chmod 600 passwd.ldif

If you don't have any user passwords in your ldif file, try the command with an explicit environment variable set: ETC_SHADOW=/etc/shadow ./migrate_passwd.pl /etc/passwd passwd.ldif. This should ensure that the script find the /etc/shadow file, which most probably holds your passwords.

Debian Woody's schema files do not provide the objectClass "mailRecipient". Instead, it is called "inetLocalMailRecipient". Additionally, we didn't include the Kerberos schema in our slapd.conf, so we have to remove the corresponding objectClass. You can simply adapt all the entries by executing "sed" like the following:

  sed s/mailRecipient/inetLocalMailRecipient/g passwd.ldif | \
    sed '/^objectClass: kerberosSecurityObject$/d' | sed '/^krbName: /d' \
    > passwd.ldif_corrected
  chmod 600 passwd.ldif_corrected

Here is the corresponding passwd.ldif file (again with one user only, the corrected objectClass and other values):

dn: uid=max,ou=People,dc=subnet,dc=at
uid: max
cn: Markus Amersdorfer
givenname: Markus
sn: Amersdorfer
mail: THEUSERNAME@subnet.at
mailRoutingAddress: THEUSERNAME@mail.subnet.at
mailHost: mail.subnet.at
objectClass: inetLocalMailRecipient
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: account
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
userPassword: {crypt}$1$_my-password-hash-from-/etc/shadow
shadowLastChange: 12174
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash
uidNumber: 1000
gidNumber: 1000
homeDirectory: /data/home/max
gecos: Markus Amersdorfer,,,

This information can again be added to the LDAP server by executing something like the following:

  ldapadd -H ldap://ldap.subnet.at/ -D "cn=manager,dc=subnet,dc=at" -x -W -f passwd.ldif_corrected
  Enter LDAP Password:
  adding new entry "uid=max,ou=People,dc=subnet,dc=at"

Samba 2.2.x and LDAP

Samba: Introduction

Now that we have a working LDAP server to hold all our Linux-users, it would be useful to have the network's Windows machines use this database too, of course.
As no flavour of Windows (AFAIK) can access the LDAP database directly, the Windows machines (both servers and clients) will have to be part of a domain which is controlled by a Samba PDC. Thus, the Windows machines will allow access based on what the (Samba) PDC says which again makes its decisions on what the users in the LDAP database look like.
(This means, all Windows/Samba clients query the Samba-PDC. The Samba-PDC queries LDAP for entries which are "objectClass: sambaAccount".)
03-08-15: See user comment from Aug 14, 2003.

Oh, and by the way, remember that this HOWTO-document uses Debian Woody as the underlying distribution, so "Samba" refers to "Samba 2.2.3a" currently.
(Infos on Samba 3.x are as welcome and will be included here as any other feedback!)

Another add-on: You only have to install this "special LDAP-Samba version" on the machine which performs as your network's PDC. All other Samba machines should be configured to use this one Samba PDC as their "oracle" for user authentication. (You'll use options like "security = DOMAIN" and "password server = MYPDC" to accomplish this.)

Samba: Installation and Setup

Samba itself (if it's not configured to query some other server for user-authentication) can either use the smbpasswd file to hold its users or use an LDAP server to accomplish this. It's not possible to do both at the same time, you have to decide at compile time.
The default behaviour is to use the flat smbpasswd file. Debian Woody's Samba packages of course defaults to the default in this case. Conclusion: Recompilation is necessary.

  cd ~
  mkdir samba-source
  cd samba-source
  apt-get source samba
  cd samba-2.2.3a
  vi debian/rules
    --> add "--with-ldapsam \" just before "--with-msdfs"
  [ vi debian/changelog ]

  dpkg-buildpackage -b -us -uc
    [ Due to missing build-dependencies:
        apt-get install libreadline4-dev libcupsys2-dev
	  [with extra-packages "libcupsys2 libjpeg62 libtiff3g"]
        dpkg-buildpackage -b -us -uc
    ]
  cd ..
  dpkg -i samba-common_2.2.3a-13subnet_i386.deb
          samba_2.2.3a-13subnet_i386.deb
          smbclient_2.2.3a-13subnet_i386.deb
          smbfs_2.2.3a-13subnet_i386.deb
          samba-doc_2.2.3a-13subnet_all.deb

  [ Currently now packages available, please build them yourself ... ]

Mind:
In order for Samba to support ACLs, I also added "--with-acl-support" and changed in debian/config.cache the value "ac_cv_header_sys_acl_h=${ac_cv_header_sys_acl_h=no}" to "ac_cv_header_sys_acl_h=${ac_cv_header_sys_acl_h=yes}".

Again, "dpkg-buildpackage" might not compile the packages at the first time you run it due to some missing build-dependencies. apt-get install the mentioned packages and run "dpkg-buildpackage" again in this case.
Again, set the packages to HOLD using dselect or something like "echo "samba-common hold" | dpkg --set-selections".
But be aware to keep track of possible security-updates for these packages on your own from now on! (Upgrading to the possibly new packages then should be easily possible by running "dpkg -i ..." again. Make sure to have backups of your configuration before as well as to set the packages to HOLD afterwards again.)

Next, teach your LDAP server the possibilities of Samba by adding the Samba schema file and restrict the access to the users' Samba passwords using the Access Control Lists:

Run:
  cp /usr/share/doc/samba-doc/examples/examples/LDAP/samba.schema.gz /etc/ldap/schema/
  cd /etc/ldap/schema/
  gunzip samba.schema.gz
  chown slapd.slapd samba.schema
  chmod 440 samba.schema

Add to /etc/ldap/slapd.conf:
  include /etc/ldap/schema/samba.schema

Change the already exiting password ACL rule in /etc/ldap/slapd.conf:
  # access to dn=".*,dc=subnet,dc=at" attribute=userPassword
  access to dn=".*,dc=subnet,dc=at" attribute=userPassword,lmPassword,ntPassword
    [...]
  
Restart OpenLDAP:
  /etc/init.d/slapd restart

Now that you have an "LDAP capable" Samba installed and now that your OpenLDAP knows about the new attributes, of course the Samba server needs to be able to query the LDAP server for users. I tried to think of a setup which would not use "cn=manager,..." for this, but I just couldn't figure one out. The main reasons are that Samba (in some way) must be able to change the passwords (e.g. using "smbpasswd") and above all edit or even add LDAP entries (e.g. machine accounts for new SMB-clients joining the domain).

Of course, Samba has to know about this user and it's password. This leads us to the next (and one of the last) steps to do: configure smb.conf (and thus Samba and its tools) correctly to use the LDAP server properly. Here are the additions to be added to the [global] section of your Samba PDC:

/etc/samba/smb.conf, add to [global]:

  # Without SSL:
  ldap admin dn = cn=manager,dc=subnet,dc=at
  ldap server = ldap.subnet.at
  ldap suffix = ou=People,dc=subnet,dc=at

  # Plus these options for SSL support:
  #ldap port = 636
  #ldap ssl = on

Restart Samba:
  /etc/init.d/samba restart

Here is a sample smb.conf file.

BTW: As Implementing a Samba LDAP Primary Domain Controller Setup on Mandrake 9.x states, we probably don't need (and thus don't want) the overhead of encryption on the very same system where both OpenLDAP and Samba are running on. (If the two services run on different machines, you can add the two options "ldap port" and "ldap ssl" accordingly.

Last but not least, we have to tell Samba the corresponding password:

  # read -s -p "Enter LDAP Root DN Password: " LDAP_BINDPW
  # smbpasswd -w $LDAP_BINDPW
    --> output:
      Setting stored password for "cn=manager,dc=subnet,dc=at" in secrets.tdb

This way, you set an environment variable to the corresponding password and use it in the next command to tell Samba about it. (That's a very neat trick I saw at B. Milne's "Implementing Disconnected Authentication and PDC/BDC Relationships Using Samba and OpenLDAP" to keep the password from your shell's history file and similar. It will not show up anywhere :).)
"smbpasswd -w $LDAP_BINDPW" is the actual command of interest. Basically, it stores a password hash for the user of smb.conf's option "ldap admin dn" in the file /var/lib/samba/secrets.tdb.

Samba: Test your Setup

Before messing around too much with your (already existing?) LDAP users, you might want to test if the new setup works properly.
If you don't want to do this, just go on and proceed with the next section Samba: Add (Windows) Users.

As Samba needs a "Linux user" for/below every "Samba user", we simply add one to the local flat files (passwd|shadow|group). Not saving it in LDAP at this time yet helps keeping things seperated, simple and "a way which is already known".
Nevertheless, the corresponding Samba user to be added will - of course - be stored in the LDAP database, 'cause that's what we want actually.

Add the "Linux user" (to local flat files):
  # adduser --no-create-home maxsmb
      [e.g. password: 12345]

Add the "Samba user" (to LDAP):
  # smbpasswd -a maxsmb
    --> output:
      New SMB password: abcde
      Retype new SMB password: abcde
      LDAP search "(&(uid=maxsmb)(objectclass=sambaAccount))" returned 0 entries.
      Added user maxsmb.

Check yourself:
  # getent passwd | grep maxsmb
  # ldapsearch -b "ou=People,dc=subnet,dc=at" -LLL -D "cn=manager,dc=subnet,dc=at" -W -x "(uid=maxsmb)"

One can now access the Samba server using this user, change its password using "smbpasswd $user", etc. - business as usual. The "only" difference is that now the LDAP server is used to hold the information which is usually stored in smbpasswd:

  client$ smbclient -L //ldap
  Password:
  Anonymous login successful
  Domain=[SUBLDAP] OS=[Unix] Server=[Samba 2.2.3a-12 for Debian]
        Sharename      Type      Comment
        ---------      ----      -------
        tmp            Disk
        maxsmb         Disk
        IPC$           IPC       IPC Service (yellow server (Samba 2.2.3a-12, LDAP-Test))
        ADMIN$         Disk      IPC Service (yellow server (Samba 2.2.3a-12, LDAP-Test))
                                                                                                   
  client$ smbclient //ldap/tmp
  added interface ip=193.170.141.119 bcast=193.170.141.127 nmask=255.255.255.128
  Password:
  Anonymous login successful
  Domain=[SUBLDAP] OS=[Unix] Server=[Samba 2.2.3a-12 for Debian]
  smb: \>
                                                                                                   
  client$ smbclient //ldap/maxsmb
  added interface ip=193.170.141.119 bcast=193.170.141.127 nmask=255.255.255.128
  Password:
  Anonymous login successful
  Domain=[SUBLDAP] OS=[Unix] Server=[Samba 2.2.3a-12 for Debian]
  tree connect failed: NT_STATUS_WRONG_PASSWORD
                                                                                                   
  client$ smbclient //ldap/maxsmb -U maxsmb
  added interface ip=193.170.141.119 bcast=193.170.141.127 nmask=255.255.255.128
  Password: abcde
  Domain=[SUBLDAP] OS=[Unix] Server=[Samba 2.2.3a-12 for Debian]
  smb: \>

Now that everything is proven to work properly, you can extend your LDAP users to become Samba capable.
But before doing that, don't forget to remove this section's test user "maxsmb":

  # ldapdelete -D "cn=manager,dc=subnet,dc=at" -W -x "uid=maxsmb,ou=People,dc=subnet,dc=at"
  # deluser --remove-home maxsmb

Samba: Add (Windows) Users

In order for Samba to allow access to shares for certain users (and don't allow for others), it needs to know these users. If you just have a few of them, there's nothing easier than to simply add them:

  # smbpasswd -a $user

This command seems to perform an LDAP search for an already existing entry matching "(&(uid=maxsmb)(objectclass=sambaAccount))".
If none is found, it either creates the entire user (as is the case in the example in section Samba: Test your Setup), or it uses an already existing normal Unix-user and adds the corresponding Samba attributes.
If it finds an entry matching its query (which means the user already exists as a Samba-user), it simply updates the password-hashes (no matter whether it's invoked as "smbpasswd $user" or "smbpasswd -a $user").

If you have lots of users already existing in the LDAP tree (e.g. due to migrating them as described above), or if you have lots of "Windows-users" to add, you'll need a script to do the work:

  # Warning: This should work, but I didn't try it in large scale:

  ldapsearch -b "ou=People,dc=subnet,dc=at" -LLL -D "cn=manager,dc=subnet,dc=at" \
    -W -x '(&(objectClass=posixAccount)(!(objectClass=sambaAccount)))' | grep "uid: " \
    | awk '{print $2}' > linux-and-not-samba-users.txt
  for user in `cat linux-and-not-samba-users.txt`; do echo $user `makepasswd` \
    >> users-with-samba-passwords.txt; done
  sed s/^/"smbpasswd -a "/ users-with-samba-passwords.txt > make-them-samba-users.sh

  chmod 600 users-with-samba-passwords.txt
  chmod 700 make-them-samba-users.sh
  ./make-them-samba-users.sh

This takes all Linux-users which are not Samba-users already, makes them Samba-users and assigns them a random password (creating the random passwords using makepasswd might take a while!). You can easily tell your users about their passwords as they are stored in users-with-samba-passwords.txt.
Mind that the filter is included in '...' and not "...". (Somehow the BASH messes something up when using double-quotes, even when escaping & and ! using \.)

Samba: Migration Summary

Samba: Join Windows-Workstations to our Samba-PDC Domain

03-08-13:
In contrast to the initial release of this howto, I meanwhile figured out how to have a machine account automatically be added to the LDAP-tree.

Both possible ways, adding the account manually or have Samba add it automatically (if it doesn't exist already), use this script I wrote: create-machine-account.sh.
ToDo: Some parts of the script should be rewritten to clear things up and make the script simpler (e.g. by using functions to print the status messages). It's a little mess currently, but it works.

  1. To add the machine manually, run "./create-machine-account.sh NewMachineName$ I". Option "I" activates the interactive mode (printing status messages to stdout and possibly querying you for the rootbinddn-password).
  2. To have Samba add the account automatically while the machine joins the domain, add the following option to your smb.conf's [global] section:
    add user script = /usr/local/sbin/create-machine-account.sh %u
        

What create-machine-account.sh does basically boils down to:

Usage: # ./create-machine-account.sh NewMachineName$ <I> (WITH the machine account's trailing "$"). In "non-interactive" mode (i.e. without option "I"), all the script's status messages are logged using /usr/bin/logger.
Mind: At the beginning of the script are three options which can be changed, but are consistent with our setup here by default.

Joining the domain on the Windows machine works as usual. Just perform steps 1 and 3 of this mini-Howto describing exactly that: Howto join a Windows client to a domain. (But be careful: You'll need the user "root" as mentioned in step 2. If it doesn't already exist, adding at least the "objectClass: sambaAccount" part to LDAP "is left to the reader as an exercise". I now, you probably hate this phrase as much as I do... sorry!)
You can now log on to this machine using all valid LDAP sambaAccount entries.
According to B. Milne's document it should be possible to have all "Domain Administrators" join a machine to the domain. I didn't try this yet.

BTW: Using "ou=People" is different from the smbldap-tools (smbldap-tools work-log) which use "ou=Computers,dc=,dc=" for machine accounts.
Nevertheless, searching for MachineAccounts is easy here too: just "ldapsearch" for "(gecos=MachineAccount)".

Add-on: Joining a Windows machine to the domain if the machine-account already exists works just fine too. (Thus it's possible to re-use machine-accounts in case a machine left the domain without having to delete the machine-account first.)

Samba: Join Samba-Workstations to our Samba-PDC Domain

Joining a Samba-Workstation to our Samba-PDC controlled domain involves the same steps on the server-side as does joining a Windows-Workstations. That makes sense, of course, since both systems behave the same and talk the same protocol.
This results in in the same steps as described above in section Samba: Join Windows-Workstations to our Samba-PDC Domain:

  1. On the Server: Create the Linux-User account "MachineName$"
  2. On the Server: Make it a Samba-machine-account
  3. On the Client: Join the domain

So, after creating the machine account (for both Linux and Samba) using our script "create-machine-account.sh", join the client to the domain by running the following commands on the new workstation:

  client:~# /etc/init.d/samba stop
  
  client:~# smbpasswd -j SUBLDAP -r YELLOW
  2003/08/08 20:24:31 : change_trust_account_password: Changed password for domain SUBLDAP.
  Joined domain SUBLDAP.

  client:~# /etc/init.d/samba start

Here is the according sample smb.conf of a joining workstation.
The most important options are "workgroup = SUBLDAP", "security = DOMAIN", "password server = YELLOW" and "local master = No".
Oh, and just to make sure: I performed this stuff with /etc/samba/ containing only smb.conf, and no other files such as MACHINE.SID or similar stuff.

Just for your information: Joining the domain creates the file /etc/samba/MACHINE.SID on the joining Samba machine.

Samba: Miscellaneous

So Far So Good, Part 2

After successfully setting up the server and the (Linux-) clients (see So Far So Good, Part 1), we migrated the current Linux-users of the network (which a NIS-server might have provided to the clients) using the official MigrationTools package from padl.com: We created ldif files for the base structure, the groups and the users (including shadow-passwords) and edited them (e.g. to exclude system users) prior to adding this information to the LDAP-Server.
Next, we set up LDAP-capable Samba-packages on the server only. In our network, this Samba-server will become the domain's PDC with all Windows- and Samba-clients querying this PDC. We taught the OpenLDAP-server to use the new Samba-attributes. Using some commands, we added sambaAccount's to our posixAccount's users, assigning random passwords to the users. Furthermore, we discussed joining SMB-clients (both Windows and Samba) to the domain using a custom script to set up the corresponding machine accounts.

ToDo: LDAP-Client-Interfaces

As the header indicates, this section is currently still marked "ToDo".
As basically goes for the total HOWTO: I'll add things as soon as they are ready, corrections as soon as bugs are found.

Besides the Gnome- and web-based tools mentioned here, there are also KDE tools, of course. Check out this list of Graphical LDAP tools over at the LDAP Linux HOWTO.

Directory Administrator

Directory Administrator is a GTK-based LDAP client.
Directory Administrator makes adding/editing/deleting users/groups really easy! If it wasn't for all our wish to understand what's behind all those GUI tools, one would probably use this one from the beginning already.

Debian packages for a current version backported to Woody can be found in Christof Meerwald's Debian section.

GQ

GQ is a GTK-based LDAP client.
GQ is great to browse your overall LDAP tree and get a good feeling of what's where. Easy access to all available attributes etc.

Debian packages for a current version backported to Woody can be found in Christof Meerwald's Debian section.

ToDo: phpLDAPadmin

Citing the homepage:
phpLDAPadmin is a web-based LDAP application for managing all aspects of your LDAP server."

(phpLDAPadmin was formerly known as "DaveDAP". Citing from its description: "DaveDAP is a web-based LDAP admin tool written in PHP. You can browse your LDAP tree, create, delete, edit, and copy objects, perform searches, and view your server's schema. You can even copy objects between two LDAP servers and recursively delete or copy entire trees.")

ToDo: Miscellaneous

Miscellaneous


Part II: Using OpenLDAP on Debian Sarge to serve Linux Users

Table of Contents (Part II: Sarge)

Part II - Sarge: Introduction

Part II - Sarge: On the Versions ...

As much as I would have liked to re-work this document for Debian 3.1 ("Debian Sarge"), I unfortunately neither have the time nor the resources to do so. (I moved to the UK, and I do not have access to e.g. the necessary hardware resources here anymore.)

Still, I would like to share my experiences with a preliminary version of Debian Sarge, dated back about half a year ago to January 2005.
Note though that my notes below are based on LDAP packages of versions 2.1.xx, while the final Debian Sarge ships LDAP packages of versions 2.2.xx.
Since, thus, the following work-log is currently not based on the final version of Sarge, please treat it as such: A work-log.
(This state of information is also reflected in the state of structuring: It's more a "bunch of" than a "list of". Sorry 'bout that ... should I get the time and resources again to work on this any further, I'll gladly do so.)

Part II - Sarge: The Differences to the Woody Documentation Above

With the Sarge version, I tried to stick more to the Debian default packages as they are. The default configuration is not removed anymore, for example. Recompilation of the packages is also not necessary ...

If you're running Debian Sarge, give the descriptions below a chance. For more information on some issues, please check the Woody documentation above. (The general LDAP principles are still the same, of course!)

Part II - Sarge: Feedback!?

Comments and corrections are welcome indeed, as always!

Part II - Sarge: The Work-Log

Part II - Sarge: Basic Installation and Configuration

Install the packages "slapd" (2.1.30-3) and "ldap-utils" (2.1.30-3) as well as the dependencies and recommendations:

  # dselect
  Reading Package Lists... Done
  Building Dependency Tree... Done
  The following NEW packages will be installed:
    db4.2-util ldap-utils libiodbc2 libltdl3 libsasl2-modules slapd
  0 upgraded, 6 newly installed, 0 to remove and 0 not upgraded.
  Need to get 1559kB of archives.
  After unpacking 4026kB of additional disk space will be used.
  Do you want to continue? [Y/n]

Concerning the configuration of these packages:

The only thing to change in the /etc/ldap/slapd.conf file is to add (near the beginning of the file) the "misc.schema" to be used:

  ######################### /etc/ldap/slapd.conf #########################
  # Note: We need this to be able to have entries with attributes such as
  #       "mailRoutingAddress" (which we need as we'll use the LDAP-server
  #       to host the mail-users and -domains for the Postfix SMTP server).
  # 
  # [...]
  include /etc/ldap/schema/misc.schema
  # [...]

Don't forget to restart the LDAP server afterwards:

  # /etc/init.d/slapd restart

Part II - Sarge: LDAP Clients

In order to connect to the server from an Ubuntu Linux client (which is what I use on my client machine), simply install the "ldap-utils" package and run something like:

  $ ldapserach -x -b "dc=example,dc=com"

If you want to connect as the LDAP-admin from anywhere on the network, use something like this

  $ ldapsearch -b "dc=example,dc=com" -LLL -D "cn=admin,dc=example,dc=com" \
    -H "ldap://yourserver.example.com" -W -x

If you want a graphical client, install e.g. the package "gq". Ubuntu 4.10 (aka "Warty") comes with version 1.0beta1-1. For some reason, I could not add a new server to its config using the graphical menu. The solution is to fire up your editor and add the following section to your (already existing as you should start once and stop GQ first) ~/.gq file:

    <ldapserver>
        <name>peach</name>
        <ldaphost>yourserver.example.com</ldaphost>
        <ldapport>389</ldapport>
        <basedn>dc=example,dc=com</basedn>
        <binddn>cn=admin,dc=example,dc=com</binddn>
        <pw-encoding>Base64</pw-encoding>
        <search-attribute>cn</search-attribute>
    </ldapserver>

You can now modify the server settings, but with the above config, you should already be able to connect to the server as "admin". Note though that all your data (including the password) is transferred in cleartext!

Part II - Sarge: Database Population

Next, add some test-data to your LDAP database, using the following file "basic-test-user.ldif":

dn: ou=People,dc=example,dc=com
objectClass: organizationalUnit
ou: People

dn: ou=Group,dc=example,dc=com
objectclass: top
objectclass: organizationalUnit
ou: Group

dn: uid=maxldap,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
objectClass: organizationalPerson
objectClass: inetLocalMailRecipient
uid: maxldap
cn: Markus Peach LDAP User Amersdorfer
sn: Amersdorfer
givenname: Markus Peach LDAP User
title: Dipl.-Ing.
departmentNumber: IT
mobile: 012-345-6789
postalAddress: AddressLine1$AddressLine2$AddressLine3
telephoneNumber: 1234-567890
facsimileTelephoneNumber: 012-345-6789
userpassword: {CRYPT}SOME-CHARACTERS-OF-YOUR-PASSWORD-HERE
labeleduri: http://homex.subnet.at/~max/
mail: my.email.address@example.com
mail: my.alternate.email.address@example.com
mailRoutingAddress: my.email.account@mail.server.example.com
loginShell: /bin/bash
uidNumber: 12345
gidNumber: 12345
homeDirectory: /home_local/maxldap/
gecos: maxldap_gecos-field
description: Not Available
localityName: I dont know

dn: cn=maxldap,ou=Group,dc=example,dc=com
objectClass: posixGroup
objectClass: top
cn: maxldap
gidNumber: 12345

To add this to the running slapd-LDAP-server's database, run the following:

  $ ldapadd -f basic-test-user.ldif -D "cn=admin,dc=example,dc=com" -W -x
  Enter LDAP Password:
  adding new entry "ou=People,dc=example,dc=at"

  adding new entry "ou=Group,dc=example,dc=com"

  adding new entry "uid=maxldap,ou=People,dc=example,dc=com"

  adding new entry "cn=maxldap,ou=Group,dc=example,dc=com"

Running "slapcat" as root on your LDAP-server, you'll notice that some additional attributes such as "creatorsName" and "modifyTimestamp" were added automatically.
Note: AFAIK, you should use the "slapcat" and "slapadd" commands only when the slapd-process is stopped!

If you wanted to remove these entries again, use the following file "basic-remove.ldif":

dn: uid=maxldap,ou=People,dc=example,dc=com
changetype: delete

dn: cn=maxldap,ou=Group,dc=example,dc=com
changetype: delete

dn: ou=People,dc=example,dc=com
changetype: delete

dn: ou=Group,dc=example,dc=com
changetype: delete

and run the following command:

  $ ldapmodify -f basic-remove.ldif -D "cn=admin,dc=subnet,dc=at" -x -W
  Enter LDAP Password:
  deleting entry "uid=maxldap,ou=People,dc=subnet,dc=at"

  deleting entry "cn=maxldap,ou=Group,dc=subnet,dc=at"

  deleting entry "ou=People,dc=subnet,dc=at"

  deleting entry "ou=Group,dc=subnet,dc=at"

Part II - Sarge: Configuring NSS

  # apt-get install libnss-ldap 

You are asked questions such as "is a login needed to retrieve data from the LDAP db?" and "should the libnss-ldap configuration file be readable and writable only by the file owner?", which is all more than interesting and could be necessary if you use a non-Debian-default setup. (This might be used to harden the installation later, but at the moment, we use the defaults...)
(From one of those Debconf-dialogs: "Note: As a sanity check, libnss-ldap will check if you have nscd installed and will only set the mode to 0600 if nscd is present." Thus, it might really be a good idea to use "nscd"! See http://homex.subnet.at/~max/ldap/index.php#nss-install, section "NSCD and /etc/libnss-ldap.conf" for more details!)
The example-file /usr/share/doc/libnss-ldap/examples/nsswitch.ldap holds really good information for decent configuration of our /etc/nsswitch.conf.

Nevertheless, we'll stick with the basics at the moment and just change the existing /etc/nsswitch.conf a little bit - after making a backup of it:

  # cp /etc/nsswitch.conf /etc/nsswitch.conf_05-01-05
  # $EDIT /etc/nsswitch.conf
    [...]
    passwd:  ldap compat
    group:   ldap compat
    shadow:  ldap compat
    [...]

You should now be able to see the user via the NSS library calls:

  # finger maxldap
  Login: maxldap                          Name: maxldap_gecos-field
  Directory: /home_local/maxldap/         Shell: /bin/bash
  Never logged in.
  No mail.
  No Plan.
  
  # getent passwd|grep maxldap
  maxldap:x:12345:12345:maxldap_gecos-field:/home_local/maxldap/:/bin/bash

Great.

Part II - Sarge: Configuring PAM

In order to be able to authenticate against the LDAP server using the user's password, we need to adapt the PAM service:

  # apt-get install libpam-ldap

I basically used the same choices are as mentioned in http://people.debian.org/~torsten/ldapnss.html, as described as follows.
(Note: You could choose to use "MD5" password hashes here!? Again, this sounds like it would be a good idea, but we'll stick with "crypt" for the moment though...)

I adapted common-account, common-auth and common-password -- slightly different changes each:

# /etc/pam.d/common-account - authorization settings common to all services
# markus -- 05-01-05
# To activate LDAP support, comment the default and add the LDAP config
# markus -- 06-08-05
#  With "use_first_pass", root cannot change the password anymore (affects common-password)
#  It seems to have been replaced with "try_first_pass".
#account        required        pam_unix.so
account         sufficient      pam_ldap.so
account         required        pam_unix.so try_first_pass

# /etc/pam.d/common-auth - authentication settings common to all services
# markus -- 05-01-05
# To activate LDAP support, comment the default and add the LDAP config
# markus -- 06-08-05
#  With "use_first_pass", root cannot change the password anymore (affects common-password)
#  It seems to have been replaced with "try_first_pass".
#auth   required        pam_unix.so nullok_secure
auth    sufficient      pam_ldap.so
auth    required        pam_unix.so nullok_secure try_first_pass

# /etc/pam.d/common-password - password-related modules common to all services
# markus -- 05-01-05
# To activate LDAP support, comment the default and add the LDAP config
# markus -- 06-08-05
#  With "use_first_pass", root cannot change the password anymore (affects common-password)
#  It seems to have been replaced with "try_first_pass".
#password   required   pam_unix.so nullok obscure min=4 max=8 md5
password   sufficient pam_ldap.so
password   required   pam_unix.so nullok obscure min=4 max=8 md5 try_first_pass

(Note: As mentioned in Torsten's Howto, common-session goes unchanged... At the moment I do not know why? Shouldn't we make the ldap-changes there too?)

It is now possible to log in on the command-line using NIS-users (correct password: accept; wrong password; reject) as well as the maxldap-LDAP-user!! :)
"su" and "ssh" work too!
(Note: For "ssh" to work properly, you have to restart the ssh-service first!)

Part II - Sarge: Have the Server Processes Run as Non-root

In order to get the "slapd" process to run as a different user and group than root, check out "/etc/default/slapd" first of all.

According to /usr/share/doc/debian-policy/policy.txt.gz (package "debian-policy"), section "9.2.2. UID and GID classes", the system-UIDs 100-999 can be assigned for system-purposes on a dynamical basis. Only 0-99 must not be used on a per-machine-basis!

Thus, create the group and user as follows:

  # addgroup --system ldap
  # adduser --system --no-create-home --group ldap

Check /etc/passwd and /etc/group. There should be a group called "ldap", as well as a "ldap"-user with the GID of the just mentioned group. Both IDs should be between 100-999.

After adding "ldap" to SLAPD_USER and SLAPD_GROUP in /etc/default/slapd, trying to restart the slapd-process will result in error. (Check /var/log/syslog for more information.)
You need to enable "ldap" to read the config-file:

  # chown ldap /etc/ldap/slapd.conf

Next, change the ownership of the files under /var/:

  [<0> root@peach ldap]# ll /var/lib/ldap/ -d
  drwxr-xr-x  2 root root 4096 Jan  3 15:04 /var/lib/ldap/
  [<0> root@peach ldap]# ll /var/lib/ldap/ -a
  total 540
  drwxr-xr-x   2 root root   4096 Jan  3 15:04 .
  drwxr-xr-x  16 root root   4096 Jan  3 15:04 ..
  -rw-------   1 root root   8192 Jan  3 15:04 __db.001
  -rw-------   1 root root 270336 Jan  3 15:04 __db.002
  -rw-------   1 root root  98304 Jan  3 15:04 __db.003
  -rw-------   1 root root 368640 Jan  3 15:04 __db.004
  -rw-------   1 root root  16384 Jan  3 15:04 __db.005
  -rw-------   1 root root   8192 Jan  7 16:31 dn2id.bdb
  -rw-------   1 root root  32768 Jan  7 16:31 id2entry.bdb
  -rw-------   1 root root  97140 Jan  7 16:31 log.0000000001
  -rw-------   1 root root  12288 Jan  7 16:31 objectClass.bdb
  [<0> root@peach ldap]# ll /var/lib/slapd/ -d
  drwxr-xr-x  2 root root 4096 Jan  3 15:04 /var/lib/slapd/
  [<0> root@peach ldap]# ll /var/lib/slapd/ -a
  total 8
  drwxr-xr-x   2 root root 4096 Jan  3 15:04 .
  drwxr-xr-x  16 root root 4096 Jan  3 15:04 ..
  -rw-r--r--   1 root root    0 Jan  3 15:04 suffix_change
  [<0> root@peach ldap]# ll /var/run/slapd/ -d
  drwxr-xr-x  2 root root 4096 Jan  7 16:31 /var/run/slapd/
  [<0> root@peach ldap]# ll /var/run/slapd/ -a
  total 8
  drwxr-xr-x  2 root root 4096 Jan  7 16:31 .
  drwxr-xr-x  6 root root 4096 Jan  7 16:31 ..

  # chown ldap /var/run/ldap/ -R
  # chown ldap /var/lib/slapd/ -R
  # chown ldap /var/run/slapd/ -R

Starting slapd again should work now (# /etc/init.d/slapd start), and it should run as "ldap"-user now instead of "root":

  # ps aux|grep slapd
  ldap  2039  0.0  0.5 32916 4480 ?  Ss  16:39  0:00 /usr/sbin/slapd -g ldap -u ldap
  [...]

Part II - Sarge: Miscellaneous ToDos include ...

Apart from updating these notes to the actual Debian 3.1 release versions ... the following steps are some of those that needed to be performed next:

Part III: Miscellaneous Addons

10 May 2007

Ilja has sent me some feedback on a pre-release version Debian Etch (January 2007), whereas most of the stuff above works on Etch as well. Two steps needed to be adapted though to have slapd run under the ldap user:

  1. "chown ldap /var/lib/ldap -R" (instead of "chown ldap /var/run/ldap -R")
  2. Modify "/etc/default/slapd" to set the flag TRY_BDB_RECOVERY=no, because otherwise some files under /var/run/ldap are assigned to the root user again. This seems to be a bug in the start script of slapd.
    (I do not know whether this has changed with the final release version.)

User Comments

I would be glad to hear about your opinion, any corrections or additions. (The form is at the end of this file.)

Please add your comment:



Valid XHTML 1.0 Strict Valid CSS! Created with Vim [Blue Ribbon Campaign icon]
© Markus Amersdorfer
last modified: 2010-02-23 15:55:38
18238 hits