Current-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: openldap in netbsd

On Sat, Sep 27, 2008 at 09:06:32AM +0300, Staffan Thomén wrote:
> On Fri, Sep 26, 2008 at 10:55:54AM +0200, Adam Hoka wrote:
> >
> > Jeff Rizzo wrote:
> >> Jean-Yves Migeon wrote:
> >>> Patrick Welche wrote:
> >>>> Is there a way of getting a NetBSD client to authenticate against an
> >>>> ldap
> >>>> server? (I can't see an nss-ldap / pam_ldap - is there something else?
> >>>> xxinit was mentioned earlier...)
> >>>>
> >>>> Cheers,
> >>> If you need PAM with ldap, try security/pam-ldap in pkgsrc.
> >>>
> >>
> >> If/when anyone gets this working, it would be really, really nice to
> >> have a step-by-step how-to somewhere.  Maybe on the wiki?
> >>
> >> (I'm going to need to do this at some point, but no round tuits yet)
> >
> > I agree, that would be a really wanted guide.
> > As we have ldap libs in base system now, this should be an  
> > out-of-the-box feature with minial setup.
> I've got a (test) setup running on a pair of machines here, if you want I'll
> try to put some guidelines down; provided I don't forget about it completely..
> This has been known to happen, feel free to poke me if I leave it too long ;-)
> Staffan

Here's what I wrote, and I realized I hate writing documentation because I can
never remember what I did ;-)

Hope you appreciate it...

 $Id: netbsd-ldap-auth.txt 2 2008-09-29 12:36:44Z duck $

 OpenLDAP Authentication on NetBSD

 Author's note

 This document really describes (what I remember of installing) my system,
 with tidbits I've forgotten from various sources on the net. I can't guarantee
 that following this document you'll get a working system, but I hope it will
 provide some insights into how the thing is supposed to work. 

 Staffan Thom´en <>

 Server setup

 First things first, you'll need to set up an openldap server somewhere, this
 is fairly straightforward, as it's available in pkgsrc. The tricky bit is
 really configuring the ACL:s, since the openldap logs are incredibly hard to
 Generally it's probably a good idea to firewall it from outside and worry
 about the ACL setup later if you want to do things like let other departments
 to see your users or let the public see contact information for example.

 An example config file is included in the package
 (${LOCALBASE}/etc/opeldap/slapd.conf), and the only thing that really has to
 be added is to include some schemas for user authentication:


 These are (in pkgsrc-2008Q2) installed in
 ${LOCALBASE}/share/examples/openldap/schema, and can just be included from
 there, and tells the server which record keys (as in key-value pairs) it shall

 And that really is it for the server bit. Next comes testing it out with a few
 ldap commands.

 The basic commands of talking directly with the ldap database are ldapadd,
 ldapmodify and ldapsearch. These are in the openldap-client package, so you
 won't have to install the entire server on a client machine.

 Options you'll be using alot like -b (base) and -H (host URI) can
 conveninently be stuck in a client configuration file,
 ${LOCALBASE}/etc/openldap/ldap.conf, which will save you time and aggravation
 from having to type them all the time.
 To talk to your ldap server, try running ldapsearch;

  % ldapsearch -H ldap://my.server/

 This really means dump everything, but since we've nothing in the database
 it will respond with an error.

 To set this database up for user authentication, we'll need to lay down some
 structure. LDAP is generally a hierachial database of records with key-value
 pairs. We'll first need to tell it about our organisation and then add a user.

 Here we'll be using ldapadd, which reads a format called ldif. It is a flat
 text format that looks something like this:

  dn: cn=example,dc=org
  objectClass: dcObject
  objectClass: organization
  objectClass: top
  o: Example Organisation
  dc: example

  dn: ou=groups,dc=example,dc=org
  objectClass: top
  objectClass: organizationalUnit
  ou: groups

  dn: ou=people,dc=example,dc=org
  objectClass: top
  objectClass: organizationalUnit
  ou: people

 The text above define three records, they start with a distinguished name
 of the record (dn:), which is a unique identifier for the record.

 "cn=example,dc=org" is the root of this organisation, with a common name (cn)
 example and a domain component (dc) of org.
 Next come the objectClass lines which tells us that this is domain component
 object, an organisation object and a top-level object.
 We then have an organisation (o:) line which is a descriptive text and finally
 a domain component line (dc:) which is the stored value for the dc (same as in
 the distinguished name).

 Following this are two records which define something called in ldap terms
 organisational units, and as you see from the dn:, essentially two branches
 of the main tree. They are here to be used for the user groups (yes, like
 /etc/groups) and the actual users. 
 If you want you can just stick all of this in one file (even the user below)
 and add it with ldapadd -f file.ldif, this will create the initial structure
 of your database.

 Adding a group and then a user user is no more difficult, you just have to
 fill out the right fields.

  dn: cn=ldapusers,ou=groups,dc=example,dc=org
  objectClass: top
  objectClass: posixGroup
  cn: ldapusers
  gidNumber: 101
  memberUid: bill
  memberUid: george

 A group named ldapusers with the number 101, and the secondary users bill
 and george (these are of course not required).

  dn: uid=test,ou=people,dc=example,dc=org
  objectClass: top
  objectClass: posixAccount
  objectClass: inetOrgPerson
  uid: test
  uidNumber: 2000
  gidNumber: 101
  o: Example Organisation
  cn: Test User
  givenName: Test
  sn: User
  gecos: Test User,3b,+358800128128,+35801234567
  loginShell: /bin/ksh
  homeDirectory: /home/test
  displayName: El Magnifico Test User

 A user with the uid test, belonging to group ldapusers (101); o: is the same
 as the root record above and the others apart from sn (surname) is fairly
 The GECOS field contains comma separated values, apparently it's pulled
 straight into the client system.

 The fields actually required by the schemes are:


 LDAP can store multiple roots and each user entry for example can be more than
 just the login information, as above it also mentions email, phone numbers and
 so on for our test user, and it can also include binary data like a mugshot
 and them playing the corporate theme on banjo. As far as authentication is 
 concerned, we've got what we want though.

 So far so good, this should not cause much trouble to set up, I believe I've
 covered everything required; the thing I had most problem with in relation to
 the database itself was that it was so unstructured, you have to provide all
 the structure yourself.

 Client Setup

 In order to log in on a NetBSD system we need to provide two things, 
 a way for the system to authenticate you and a way for it to find out what
 your group, user id, etc. is.

 The first part of this, authentication is taken care of by PAM (or possibly
 by some BSD auth scheme, but this is not yet implemented as far as I know.)

 The second part is done via libc and the NSS subsystem.

 In order to do this, we need to provide some plugins for either system that
 enables LDAP support in them. The plugins are in pkgsrc and are called



 Once these are installed, you can either link them, copy or use in place from
 ${LOCALBASE}/lib and ${LOCALBASE}/lib/security into /usr/lib and
 /usr/lib/security respectively. I prefer to use symbolic links because then
 any upgrade I make will automatically have the latest version already in place.

 Before we go any further, I'd like to introduce some security into the mix;
 up til now we've talked to the ldap server without any limitations and what's
 called anonymous binds, i.e. not logged in.

 XXX can anonymous binds actually write to a db without ACLs?

 This is an ldap user, just like the test user outlined above, since the ldap
 database can authenticate against itself. (You don't have to, but I haven't
 explored the other possibilities such as SASL)

 So we'll create a user called nss

  dn: cn=nss,dc=example,dc=org
  objectClass: top
  objectClass: inetOrgPerson
  o: Example Organisation
  cn: nss
  sn: manager

 We'll attach a password so that not just anyone can connect, and also change
 our LDAP configuration slightly so that we use encrypted passwords.

  userPassword: {SSHA}w5aocfmGgZqq3h8AjvaZiw8WKdrRTjTi

 To generate this password I use (bundled with openldap-server) slapdpasswd

  % slappasswd -h "{SSHA}"
 And in slapd.conf add

  passsword-hash {SSHA}

 And of course you'll need to change the secret for the rootpw into something

 Note that the traffic between the ldap client and the server is still not (that
 is if you've been following this document) encrypted so this might be best to
 perform locally.

 This user will be used for ACL filtering later.
 Next we'll need to configure the LDAP part of the plugins, a convenience here
 is that since both the plugins are made by the same people, they can share a
 configuration file. They will look for ${LOCALBASE}/etc/nss_ldap.conf and
 ${LOCALBASE}/etc/pam_ldap.conf, but linking them to the same file will let you
 have just one place to configure (and protect for your ldap user password)

 The important bits in this file is the base setting and the uri for your
 ldap server:

  base dc=example,dc=org

  uri ldap://my.server/

 Next we need to tell it who it should contact the ldap database as:

  binddn cn=nss,dc=example,dc=org

  bindpw unencrypted-password

 And if you want to be able to change passwords as root without knowing the
 user's password in advance (with passwd, using ldapmodify you can still just
 set it, if you bind with the credentials to do it (see ACLs).)

 I haven't mentioned this user before, it's the database's root user, allowed
 to do anything;

  rootbinddn cn=root,dc=example,dc=org

 The password for this will not be in this file, but in a separate file called
 ${LOCALBASE}/etc/nss_ldap.secret or for pam; ${LOCALBASE}/etc/pam_ldap.secret
 *) not sure about this, but my system has both, linked together

 Finally we will set the password exchange method to exop;

  pam_password exop

 This is the OpenLDAP extended method and while the passwords will still be sent
 in the clear, they are encrypted with the database's scheme in the database.

 So while you can use ldapsearch to get the data (though ACLs can prevent this
 if properly set up) it will still only be a hash.

 That's it for configuring the plugins so far.


 The next change we will need to do is to enable the ldap module in


  group:        files
  passwd:       files

  group:        files ldap
  passwd:       files ldap

 This will enable you to have local accounts as well as ldap users.
 You could test this out now, by running the getent program;

  % getent group

 Will present you with a list of all the groups in the system, with the ldap
 group 'ldapusers' we created earlier tacked on to the end of the list.

  % getent passwd

 And this will show you the user list, with the ldap user 'test' at the end.


 PAM keeps it's configuration files in /etc/pam.d/, these are divided into
 individual files per each pam service in the system; most are just including
 system but some need special attention.

 On my system I have the following changes from the stock netbsd setup:


  # $NetBSD: sshd,v 2005/03/19 17:45:49 tron Exp $
  # PAM configuration for the "sshd" service
  # auth
  auth            required  no_warn
  auth            sufficient
  auth            sufficient     no_warn try_first_pass
  # pam_ssh has potential security risks.  See pam_ssh(8).
  #auth           sufficient      no_warn try_first_pass
  auth            required     no_warn try_first_pass
  # account
  account         required
  account         sufficient
  account         required
  account         required
  # session
  # pam_ssh has potential security risks.  See pam_ssh(8).
  #session        optional
  session         sufficient
  session         required
  # password
  password        sufficient     no_warn try_first_pass
  password        sufficient
  password        required     no_warn try_first_pass


  # $NetBSD: su,v 1.5 2005/03/01 16:28:46 christos Exp $
  # PAM configuration for the "su" service
  # auth
  auth            sufficient
  auth            sufficient           no_warn
  auth            sufficient             no_warn
  auth            sufficient              no_warn try_first_pass
  auth            requisite            no_warn group=wheel 
root_only fail_safe
  #auth           sufficient            no_warn 
group=rootauth root_only fail_safe authenticate
  auth            required             no_warn 
try_first_pass nullok
  # account
  account         required
  account         include         system
  # session
  session         required


  # $NetBSD: system,v 1.6 2005/03/03 02:12:32 christos Exp $
  # System-wide defaults
  # auth
  auth            sufficient
  auth            sufficient             no_warn try_first_pass
  auth            required             no_warn 
try_first_pass nullok
  # account
  account         sufficient
  account         required
  account         required
  # session
  session         sufficient
  session         required          no_fail no_nested
  # password
  password        sufficient
  password        sufficient             try_first_pass
  password        sufficient             try_first_pass
  password        required             prelim_ignore

 The last bit here with pam_deny, is a bit special, it is what enables you to
 change passwords for both local users and those in the ldap database with the
 passwd command. pam_deny with the prelim_ignore flag is needed, else pam will
 will fail in the preliminary phase (it is always run trough twice) and you will
 not be able to change passwords.

 In order to use this you need to patch your pam_deny
 (/usr/src/lib/libpam/modules/pam_deny.c) with the patch by
 Edgar Fuß <>:

 The original message describing the problem is here:

 Securing your system

 As far as the document goes now, this setup is unprotected in that anyone
 listening in to the packets travelling trough your network would be able to
 find the unencrypted messages of your ldap users. Not a happy thought.

 So we'll want to enable SSL encryption of the traffic between your clients and
 the server.

 In order to do this you will need to create an SSL certificate for your server
 and also distribute it to the client machines, so that they will be able to 
 certify the authenticity of the server.

 We'll also need to configure slapd to use it, I put my keys in the /etc/openssl
 hierachy, since it seemed made for it.

  TLSCipherSuite          HIGH:MEDIUM:+SSLv2
  TLSCertificateFile      /etc/openssl/certs/openldap.pem
  TLSCertificateKeyFile   /etc/openssl/private/openldap.pem
  TLSCACertificateFile    /etc/openssl/certs/openldap.pem

 And we'll also have to change the way slapd is started, so add this to your

  slapd_flags="-h ldaps://"

 Note that this will make slapd answer only to ldaps!

 Next we'll need to change the clients setup so that they will use ldaps.
 Enable ssl in ${LOCALBASE}/etc/{nss_,pam_}ldap.conf;

  ssl on

 Next if you're like me using the ${LOCALBASE}/etc/openldap/ldap.conf file,
 telling the client libs where to find the cert file is enough, we don't have
 to put it in the nss/pam config:

  URI           ldaps://my.server
  TLS_CACERT    /etc/openssl/certs/openldap.pem

 If you can still use getent, encryption is happening. You can of course also
 tcpdump your network traffic to see what's going on.


 I left access control lists of the server to the last, because they are the
 easiest to get wrong and often cause problems that you might attribute to other
 things in the various setups.

 The syntax is fairly straightforward;

 acceess to [something] by [someone] [access]

 The order is important; if something matches, later tests will not be run.

 The one I use looks like this:

  # Protect passwords from prying eyes
  access to attrs=userPassword
        by dn="cn=nss,dc=example,dc=org" write
        by anonymous auth
        by self write
        by * none
  # set read-only attributes
  access to attrs=uidNumber,gidNumber,uid,homeDirectory
        by dn="cn=nss,dc=example,dc=org" write
        by self read
        by * read
  # For all else, let the user edit his own entry and everyone else watch
  access to *
        by dn="cn=nss,dc=example,dc=org" write
        by self write
        by * read
 Note that access to the user password can be set to auth; so that the database
 can authenticate a user without letting them see the password hash using an
 anonymous bind.

Staffan Thomen 1024D/7C7E2EF8
Sed quis custodiet ipsos Custodes?

Attachment: pgp7RaSh8W9FT.pgp
Description: PGP signature

Home | Main Index | Thread Index | Old Index