the djb way

qmail with attitude


authentication with cvm


Link: http://untroubled.org/cvm/
Version: cvm-0.18 (2003.11.17)
Download: cvm-0.18.tar.gz
Requirements: bglibs-1.011.tar.gz (2003.12.01)
Other: GPL

Bruce Guenter's cvm package provides a set of Credential Validation Modules. These provide flexible authentication services for a number of djb services --qmail and otherwise-- all through a consistent interface.

A prerequisite to the cvm package is Guenter's djb-like library, bglibs. Download and unpack the current bglibs release into a convenient build directory. The following incantation will then build and install the package:

$ cd bglibs-1.011
$ make
$ ./instshow | less
$ su
# ./installer
# ./instcheck

The procedure is almost "djb classic", and the build will fly. The ./instshow command is optional, and will show you exactly what will be installed where. A nice touch.

The installation will result in a set of include files under /usr/local/bglibs/include, while the set of libraries will be installed under /usr/local/bglibs/lib. (To set up a different location, just edit conf-home a la djb, then rebuild and reinstall.)

Now download and unpack the latest cvm package into a convenient build directory. The build/install sequence is exactly the same as above:

$ cd cvm-0.18
$ make
$ ./instshow | less
$ su
# ./installer
# ./instcheck

This will result in a set of binaries installed in /usr/local/bin, include files under /usr/local/include/cvm/, and some libs in /usr/local/lib/libcvm-*.

The toys are installed, now we can play with them.

cvm architecture

The cvm package itself includes 2 useful authentication modules:

The cvm-pwfile uses a password database with the same semantics as /etc/passwd, and can be used to segregate the needs of a credential validation service from login account access.

The package also includes a useful cvm client, cvm-checkpassword. This client has the same interface as the checkpassword utility we installed for the qmail-pop3d service, and we will show how it may be used as a drop-in replacement.

A cvm module provides a specific form of authentication to a client, such as looking up username and password in /etc/password. A cvm module can be set up to respond to client requests via different channels, or contact modes:

contact mode module setup client usage
command
line
N/A cvm-client \
cvm-command:
/path/to/module
domain
socket
cvm-module \
cvm-local:
/path/to/socket
cvm-client \
cvm-local:
/path/to/socket
UDP
socket
cvm-module \
cvm-udp:
hostname:port
cvm-client \
cvm-udp:
hostname:port

Note the symmetry in setting up a module, and the usage by the client.

Command-line invocation of a cvm module is the simplest to illustrate, and may be set up as:


...
  cvm-checkpassword cvm-command:/usr/local/bin/cvm-unix
...

The command-line invocation can also be shortened to:


...
  cvm-checkpassword /usr/local/bin/cvm-unix
...

Here the client is cvm-checkpassword, using the module cvm-unix, directly from the command-line. The module provides credential authentication from /etc/passwd, and the client has an interface that matches the specifications of Bernstein's checkpassword.

By mixing and matching clients with cvm modules, programmers, applications, and sys-admins have enormous flexibility in setting up authentication mechanisms. For example, cvm modules are available using PostgeSQL and MySQL databases. Later on we will also see some CVM that provide frontends for SMTP-AUTH and IMAP servers.

qmail-pop3d with cvm

As a concrete illustration of cvm, we will install an authentication service on a local domain socket. Of course, we'll run it as a daemontools service, with the inelegant name cvm-unix.local. This will use the cvm-unix module for standard /etc/passwd authentication, listening for client requests over a local domain socket.

As usual, make new directories for the service definition:

# mkdir -p /var/svc.d/cvm-unix.local/log

Then the "run" script in /var/svc.d/cvm-unix.local/run:


#!/bin/sh
# cvm-unix.local/run
# daemontools run script for cvm-unix authentication service
# CVM "unix" authentication (/etc/passwd)
# **communicating on local domain socket**
# ===
CVM_SOCKET="/tmp/.cvm-unix.local"
exec 2>&1
echo "*** Starting cvm-unix.local service..."
echo "*** >> configured for domain socket: ${CVM_SOCKET}"
exec /usr/local/bin/cvm-unix cvm-local:${CVM_SOCKET}

### that's all, folks!

Make sure the script is executable. This will run the cvm-unix module, configured to listen to the Unix domain socket, /tmp/.cvm-unix.local.

You'll want the usual multilogger, in /var/svc.d/cvm-unix.local/log/run:


#!/bin/sh
# cvm-unix.local/log/run
# multilogger for cvm-unix authentication service
exec setuidgid multilog multilog t /var/multilog/cvm-unix.local

### that's all, folks!

Make executable and set up the multilog directory:

# mkdir /var/multilog/cvm-unix.local
# chown multilog /var/multilog/cvm-unix.local

Link the service to start it up:

# ln -s /var/svc.d/cvm-unix.local /service/cvm-unix.local

Presto! You now have an /etc/passwd authentication service, listening on /tmp/.cvm-unix.local. To use it with your POP3 service, change the "run" script for qmail-pop3d to look like this:


#!/bin/sh
# qmail-pop3d/run
# daemontools run script for qmail pop3 service
# ** using cvm authentication service **
# ===
POPDIR="./.QMAIL.POP/"
CONLIMIT=31
HOSTNAME=`head -1 /var/qmail/control/me`
CVM="cvm-local:/tmp/.cvm-unix.local"

exec 2>&1
echo "*** Starting qmail-pop3d..."
echo "*** >> configured for maildir: ${POPDIR}"
echo "*** >> cvm module: ${CVM}"
exec env -i PATH="/var/qmail/bin:$PATH" \
  envuidgid qmaild softlimit -m 3000000 \
    tcpserver -v -HR -l0\
    -U \
    -c ${CONLIMIT} \
    -x /etc/tcprules/pop3.cdb \
    0 110 \
      qmail-popup ${HOSTNAME} \
        /usr/local/bin/cvm-checkpassword ${CVM} \
          qmail-pop3d ${POPDIR}

### that's all, folks!

The key changes are rendered in bold. The POP3 service will now use the cvm authentication service we set up above. The multilogger on the cvm-unix.local service will then show you what is happening:

$ watchlog cvm-unix.local
2004-01-23 15:42:19.174864500 *** Starting cvm-unix.local service...
2004-01-23 15:42:19.176751500 *** >> configured for domain socket: /tmp/.cvm-unix.local
2004-01-23 15:42:19.177293500 Starting.
2004-01-23 15:50:55.195436500 + wcm@localhost
2004-01-23 15:52:55.282418500 - bilbo@localhost

Log entries marked with "+" were successfully validated; those marked with "-" failed.

Remember the Binc IMAP service? Since it also uses the /bin/checkpassword interface, you can convert it to use the cvm-checkpassword client as well.


Copyright © 2003, 2004 Wayne Marshall.
All rights reserved.

Last edit 2004.10.04, wcm.