authpam program arg1 arg2... authpwd program arg1 arg2... authshadow program arg1 arg2... authuserdb program arg1 arg2... authvchkpw program arg1 arg2... authcram program arg1 arg2... authmysql program arg1 arg2... authldap program arg1 arg2...
These modules read an account name and password from an external application, then return an indication to the external application whether or not the account name and password is valid. These modules cannot be normally executed from the command line because they expect to be executed by a separate application, which provides authentication information via environment variables and specially prepared pipes.
These authentication modules are usually installed automatically by an application that uses them. Not every one of these modules will be installed. Different modules implement different ways of authenticating the account name and password. Only the modules that are compatible with your system will be installed by default.
authpwd
validates the account name and password against your
/etc/passwd
file.
authshadow
validates the account name and password against
your /etc/shadow
file.
authuserdb
validates the account name and password against
your userdb(8)
database.
authcram
also uses userdb(8)
, but implements a
challenge/response authentication mechanism (CRAM), instead of the traditional
userid/password.
authpam
validates the account name and password using your
Pluggable Authentication Module (PAM) library. authpam
allows
PAM modules to be used to authenticate passwords by any application that uses
this authentication library.
authvchkpw
supports existing vchkpw-based virtual domain
setups. New installations should use the userdb(8)
database.
authldap
is an experimental module that uses LDAP for
authentication. authldap
will authenticate clear-text or crypt-ed
passwords in an LDAP database. If clear-text passwords are used,
authldap
will also be able to handle CRAM authentication, if the
application that uses this authentication library supports CRAM
authentication. See below for more information.
authmysql
is another experimental module that authenticates
against a MySQL table. See below for more information.
As previously mentioned, only those modules that are appropriate to your
particular system will be installed. The authpam
module will be
installed only if your system supports PAM authentication.
authldap
will be installed only if LDAP client libraries are
available. authpwd
and authshadow
will not be
installed if you have PAM authentication or LDAP authentication.
authvchkpw
is usually installed only if your system has the
vpopmail/vchkpw account. authuserdb
is usually installed in any
case. authcram
is installed only if the application that uses
this authentication library supports CRAM authentication.
authmysql
is usually installed if MySQL client libraries are
found, and authvchkpw
is not installed.
AUTHLDAP
authentication moduleThis section applies if you have the authldap
authentication
module installed. This is an experimental authentication module, and may not
be stable.
The authldap
authentication module reads a configuration file.
The configuration file tells authldap
where to obtain the
information that it needs. A default configuration file will be installed in
${sysconfdir}/courier-imap.authldaprc
.
It will be necessary to edit this file in order to properly configure
authldap
. This configuration file contains a list of settings,
one per line. Each line starts with the name of the setting, followed by one
or more whitespace characters, followed by the setting value. Leading or
trailing whitespace is not allowed.
Comments in the default configuration file describe what each setting does.
LDAP_SERVER
, LDAP_PORT
, LDAP_BASEDN
,
LDAP_BINDDN
, and LDAP_BINDPW
specify your LDAP
server's coordinates. LDAP_TIMEOUT
sets the timeout for the LDAP
query.
The LDAP query is keyed by the E-mail address. The LDAP_MAIL
settings sets the LDAP attribute that is searched for, which should be "mail".
The E-mail address should be of the form user@domain
. If the
domain is missing, authldap appends LDAP_DOMAIN
to the query.
authldap
will need to obtain the following attributes: the
account's home directory, user and group ids, and the account password. These
attributes are required. The password can be a clear-text password, or a
crypt-ed password.
There are also several optional attributes which, if present, will be used: the full name of the user, and the location of the user's main mailbox. If the mailbox location is not specified, the default location, as defined by the system administrator, will be used.
The configuration file lists which LDAP attributes contain which
properties. If all your accounts share the same global user and group IDs,
which may be the case if you are authenticating access to a large number of
virtual accounts, you can set the global user and group ID with the
LDAP_GLOB_UID
and LDAP_GLOB_GID
setting. Otherwise,
you must define LDAP_UID
and LDAP_GID
to be the LDAP
attributes that contain the numerical user and group IDs.
LDAP_HOMEDIR
specifies the name of the required LDAP attribute
which contains the account's home directory, LDAP_MAILDIR
specifies the name of the optional attribute that specifies the location of
the default mailbox. If your virtual accounts have no home directory, set both
LDAP_HOMEDIR
and LDAP_MAILDIR
to the same LDAP
attribute that specifies the location of the virtual account's mailbox.
LDAP_FULLNAME
is an optional LDAP attribute. Not every
application that uses this authentication library will need it.
You must define either LDAP_CLEARPW and LDAP_CRYPTPW. It is possible to
define both of them, but, in practice, only one of them needs to be defined.
If you store clear-text passwords, set LDAP_CLEARPW
to the name
of the LDAP attribute that holds the clear-text password. If you store
crypt-ed passwords in LDAP, set LDAP_CRYPTPW
to the name of the
LDAP attribute that holds the crypt-ed password.
If you store clear-text passwords, authldap
will be able to
carry out CRAM authentication. Only userid/password authentication is possible
if crypt-ed password are used.
AUTHMYSQL
authentication moduleThis section applies if you have the authmysql
authentication
module installed. This is an experimental authentication module, and may not
be stable.
authmysql
functions like authldap
, but uses a
MySQL The authmysql
authentication module reads a configuration
file. The configuration file tells authmysql
where to obtain the
information that it needs. A default configuration file will be installed in
${sysconfdir}/courier-imap.authmysqlrc
.
It will be necessary to edit this file in order to properly configure
authmysql
. This configuration file contains a list of settings,
one per line. Each line starts with the name of the setting, followed by one
or more whitespace characters, followed by the setting value. Leading or
trailing whitespace is not allowed.
Comments in the default configuration file describe what each setting does. Consult the configuration file for more information.
This authentication library is used by applications that typically consist of two separate parts. The first part waits for the user to enter the account name and password. Then, it runs one or more authentication modules, which check if the account name and password is valid. The second part of the application is then executed. If the password is valid, the second part of the application runs normally. Otherwise, the first part is executed again, to try to read another account name and password.
This manual page provides generic instructions for using this
authentication library. You will need to use the documentation that comes with
each application to determine the filenames corresponding to the first, login,
part and the second, application, part. The following example assumes that the
application consists of the following programs: /usr/bin/getlogin
and /usr/bin/app
. getlogin
reads the account name
and password, and app
is the actual application.
The following command starts this application with the
authuserdb
and authshadow
modules:
/usr/bin/getlogin /usr/lib/authuserdb \ /usr/lib/authshadow \ /usr/bin/app
After obtaining the account name and password, getlogin
simply
runs the program specified by its first argument, which is
authuserdb
. The remaining command line arguments to
getlogin
are received as arguments to authuserdb
.
Note that this is not a pipe, there is no | here. authuserdb
receives the remaining arguments as its own arguments, checks the account name
and password, then runs the program specified by the first argument, which is
authshadow. authshadow
receives the remaining argument, checks
the account name and password, if necessary, then runs the program specified
by its first argument.
The protocol implemented by this authentication library permits allows multiple modules to try to authenticate the account name and password. Essentially, to start an application that uses this authentication library, you run its login part, then pass the pathnames to the authentication modules to be used as the arguments to the login part of the application. The pathname to the application part is usually the last argument. Where any module requires an option or an argument, the option or the argument is provided at the appropriate point on the command line.
Any application that uses this authentication library can use any combination of authentication modules that are installed, unless there are specific restrictions mention in the documentation for each application. All pathnames must be absolute. Pathnames relative to the current directory are prohibited.
Each authentication module runs the program specified by its first
argument, after checking the account name and password. So, in the example
given previous /usr/bin/app
will be eventually executed by the
last authentication module. Each authentication module checks if the account
name and password has already been validated by a previous authentication
module. If not, it tries to validate the account name and password by itself.
The final module, the application part itself, checks if any authentication
modules successfully validated the account name and password. If not, it will
immediately execute the login part of the application using the same arguments
that were originally used, and the process will begin again. Otherwise, if the
account password was successfully accepted by any authentication module, the
application part runs normally.
The login portion of the application, getlogin
in this
example, must be executed by the superuser. After the account password is
successfully validated, the authentication module sets its user and group IDs
of the process to the user group IDs for that account, and sets its home
directory to the account's home directory. However, if all authentication
modules rejected the account name and password, the application module,
app
in this example, will still be a superuser process when it
starts. That's fine, because the first thing it does is check if the
authentication succeeded, and, if not, it will run the login process again.
Obviously, you can't use just any application with this authentication
library. An application must be specially written to understand and use this
protocol.
Applications that use this authentication library are usually network
services, and must be started in response to a network connection. There are
several ways to do that. One way is to use the inetd(8)
daemon.
Here is a sample entry in /etc/inetd.conf
for a hypothetical IMAP
server that uses this authentication library:
imap stream tcp nowait root /usr/bin/imaplogin /usr/bin/imaplogin /usr/lib/authpam /usr/bin/imapserver
This should all be entered on one line in /etc/inetd.conf
.
Note that some inetd
implementations automatically infer the
argv[0]
argument from the filename. You can use those
inetd
servers by removing the second
/usr/bin/imaplogin
entry (in this particular case) ONLY if the
inetd server does NOT strip the pathname from theimplied
argv[0]
argument. The application login process
(imaplogin
in this case), MUST know its complete pathname so that
it can be executed again if the first password is rejected.
tcpserver
If you use Dan Bernstein's tcpserver
, here's an equivalent
tcpserver
startup command for this hypothetical IMAP
application:
/usr/local/bin/tcpserver -H -R 0 imap \ /usr/bin/imaplogin /usr/lib/authpam /usr/bin/imapserver &
couriertcpd
If you use the couriertcpd
server, here's an equivalent
couriertcpd
startup command for this hypothetical IMAP
application:
/usr/local/bin/couriertcpd -nodnslookup -noidentlookup imap \ /usr/bin/imaplogin /usr/lib/authpam /usr/bin/imapserver &
You may specify appropriate options for tcpserver
and
couriertcpd
that are right for you.
The remainder of this document defines the protocol used by these authentication modules.
The overall application that uses this authentication library is made up of at least three processes:
The first process, called a "login process", is started as a superuser process in response to a network connection, or an equivalent event. It reads the userid and password, then starts an authentication module and securely transmits this information to the authentication module.
The second process is an "authentication module" that attempts to validate the userid and password in some arbitrary fashion. Whether or not the password is authenticated, the authenticated module runs the next process. That's because the next process can be another authentication module, or the authenticated client process (see below). If one authentication module fails, another authentication module can be given a chance to authenticate the userid and password. An authentication module can also decide that other authentication modules can not be used to attempt to authenticate this userid and password, because it should be unequivocally rejected.
If the authentication module successfully validates the userid and password, it sets the process's user and group ID to the authenticated user's, then sets the current directory to the authenticated user's home directory. The authentication module may also set some additional environment variables.
The final process is called the "authenticated client" process in this documentation. Contrary to its name, it is possible that it will be called even if all modules rejected the userid and password, so the first thing it does is check whether that's the case.
If any authentication module permanently rejects a userid and password, or if the authenticated client detects that all authenticated modules rejected the userid and password, the original login process is executed again, in order to try to read another password and start the process again.
It is expected that the login process is initially started by a daemon process, and it begins with a relatively clean environment. Modules use environment variables and pipes in order to implement this authentication protocol. When the login process starts it can check these environment variables to determine if this is the first time it is run, or if it is executed again in order to read another userid and password, after the first pair was rejected.
The login process is usually invoked by some system daemon process in response to a network connection. argv[0] to the login process must be a complete pathname. Otherwise, the AUTHUSER environment variable must be set prior to running the login process, and it must contain a complete pathname. It is possible that certain systems might strip the full path from argv[0], leaving just the filename, so use AUTHUSER in that case
Any options for the login process can be specified on the command line.
The first argument after any options must be a full pathname to the first authentication module to run.
It is possible to run two authentication modules, as previously described. The complete pathname of the second module should be the next argument. Additional authentication modules may also be specified in this fashion.
The arguments to the login process end with a complete pathname to the
authenticated client process, followed by any options it requires. Here is a
hypothetical example of a complete invocation of the login process:
/usr/local/bin/readuserpass -d \ /usr/lib/authuserdb \ /usr/lib/authpam \ /usr/local/bin/dostuff -x
This example runs /usr/local/bin/readuserpass
to read the
userid and password. This process uses the -d
option. This is
followed by two modules - authuserdb
and authpam
-
they are specified as the modules which will be used to authenticate the
userid and password. /usr/local/bin/dostuff -x
is specified as
the command to execute upon successful userid/password validation.
This and the following sections provide documentation that's of interest
only if you want to write your own authentication modules. The low-level
authentication protocol is defined later. The libauth.a
and
libauthmod.a
libraries contain functions that handle all the low
level details, and provide convenient high level authentication services that
you can use to write your own authentication modules in C or C++.
Under normal conditions, the login process reads its command line arguments, and processes any options it knows about. Afterwards, the remaining command line arguments specify the next process to run.
The typical logic used by the login process is as follows:
int main(int argc, char **argv) { if (authmoduser(argc, argv, TIMEOUT, ERR_TIMEOUT)) { /* Print initial greeting */ } else { /* Error: invalid userid/password */ } /* read userid and password */ authmod(argc-1, argv+1, SERVICE, AUTHTYPE, AUTHDATA); }
This example does not use any options for the login process itself. If the
login process parses any options, they must be removed from the argc/argv
arguments to the call to the authmod
function. For example, if
the authentication user process received two options, subtract two from argc,
and add two to argv to skip over them.
The TIMEOUT argument specifies the authentication timeout, in seconds. The
authmoduser
function calls alarm to set up an alarm signal to be
delivered after the specified period of time (which will terminate this
process by default).
The authmoduser
function copies the command line arguments
into environment variables. This allows the login process to be invoked with
the same exact command line arguments in the event that the subsequent account
password is rejected, in order to start the process again.
authmoduser
checks if the environment variables are not
already set, meaning that this is the first time the login process is
executed. If so, it copies the command line arguments to environment
variables, and returns non-zero.
If the environment variables were already set, the function returns 0 in
this case after sleeping for the amount of time specified by the
ERR_TIMEOUT
argument (in seconds). Note that the
TIMEOUT
time interval will generally be a cumulative value.
authmoduser
checks the system clock, and subsequent invocation of
the login process will automatically cause authmoduser
to
subtract the time already used up during the initial invocation of the
process.
The return value from authmoduser
can be used to determine
whether a "password rejected" type of a message should be printed, or if a
greeting message should be used instead.
Afterwards, the userid and password are obtained, in some fashion, and the
authmod
function is called. The first two arguments to
authmod
must be exactly as shown. If authmoduser
received argc
and argv
, authmod
must
receive argc-1
and argv+1
. If authmoduser received
any options, argc/argv must be advanced appropriately. The next argument
specifies the first authentication module to execute, which is precisely what
the authmod
function does.
SERVICE
is a character string that specifies an
"authentication service". This is not used by all authentication modules. The
authpam
module passes this directly to the PAM library, and the
PAM library uses this value to look up a list of PAM modules to run.
AUTHTYPE
and AUTHDATA
are also both character
strings. AUTHTYPE
specifies the authentication type or format.
The contents of AUTHDATA
depend on AUTHTYPE
.
Currently, two AUTHTYPE
s are defined: "login", which specifies
the traditional userid/password authentication mechanism; and "cram-md5", that
specifies the challenge/response authentication mechanism defined by RFC 2095.
When AUTHTYPE
is set to "login", AUTHDATA
must be
set to the userid, followed by a newline character, and the password, also
followed by the newline character.
When AUTHTYPE is set to "cram-md5", AUTHDATA must be set to the base64-encoded challenge string followed by a newline character, then the base64-encoded response string, also followed by a newline character.
Before running the first authentication module, authmod
sets
up a pipe on file descriptor 3 to the first authentication module, and writes
the following to the pipe:
service<NL>AUTHTYPE<NL>AUTHDATA
<NL> represents the newline character. The pipe is immediately closed after writing this information. The authlib library does not use file descriptors 0, 1, and 2. They are preserved throughout the process.
The logic in an authentication module is usually like this:
int main(int argc, char **argv) { const char *service, *authtype; char *authdata; authmod_init(argc, argv, &service, &authtype, &authdata); /* Attempt to accept this authentication request */ if success { authmod_success(argc, argv); } if failed { authmod_fail(argc, argv) } if permanently failed { authmod_fail_completely(); } }
The authentication module calls authmod_init as the first order of
business. authmod_init
receives the argc
and
argv
arguments as main received them. authmod_init
retrieves the service, authentication type, and data, and returns them.
NOTE: There's a theoretical upper limit on the maximum number of characters read from the pipe on file descriptor 3. It is high enough that most people shouldn't worry about it (the total number of characters allowed cannot be more than 8189 characters on a typical Linux system).
The authentication module then proceeds to authenticate this request in
some arbitrary fashion. The end result must be a call to one of three
functions: authmod_success
, authmod_fail
, or
authmod_fail_completely
.
authmod_success
and authmod_fail
must receive the
argc
and argv
arguments that were received by main.
They remove argv[0] from the array, and use the remaining arguments to specify
the next process to execute.
All three functions do not return, as they functions execute either the next process specified by command line arguments, or the login process again.
Before calling authmod_success
, an authentication module must
reset its user and group id to the ones appropriate for the authenticated
account, change to the account's home directory, and perform any additional
initialization logic deemed necessary.
If authmod_success
is called, and the next process is another
authentication module, the next module's authmod_init
function
will automatically call authmod_success
itself, without returning
to the main function.
authmod_fail
should be called if the password has not been
authenticated. If the next process is another authentication module, it will
receive the service string, and authtype and authtype strings, via a pipe on
file descriptor 3, and the next authentication module will get a crack at
validating the password.
authmod_fail_completely
should be called if the authentication
module rejects the password, and the authentication module does not want to
give any other authentication modules a chance to validate the userid and
password. This is typically done if the authentication module believes that
its the only authentication module that should be used to validate this
authentication request, and that no other authentication modules should be
able to do so. authmod_fail_completely
reads the original
arguments to the login process, then runs it.
Eventually, the authenticated client process will be executed. That's the last process specified on the original command line to the login process.
The only thing that the authentication client process needs to do is to
make a call to the authmodclient()
function as the very first
order of business in main()
. authmodclient
takes no
arguments. It checks whether or not any modules successfully authenticated the
userid and password by calling authmod_success
. In any other
event, authmodclient()
automatically executes the login process
(without returning to main) to begin the authentication process again.
In addition to the authentication functions in libmodauth.a library, the libauth.a contains the following functions which may be useful when writing a new authentication module:
void authchangegroup(gid_t); void authchangeuidgid(uid_t, gid_t); void authchangeusername(const char *, const gid_t *);
An authentication module should call these function prior to calling
authmod_success
. These functions set the process's user and group
IDs. Some systems feature supplementary group IDs in addition to standard
group IDs, and you may not want the authenticated client process to inherit
any auxiliary group IDs from the superuser login process. The configuration
script for the libauth.a tries to detect if this is the case, and these
functions will include code to remove all auxiliary group IDs.
authchangegroup
changes the process's group ID to the one
specified by its argument. authchangeuidgid
changes both the
group and the user ID. authchangeusername
looks up the userid and
the groupid in /etc/passwd
. If the second argument to
authchangeusername
is not NULL, it points to a group ID which
will override the group ID specified in the system's password database for
this user. If it is NULL, the group ID and any auxiliary group IDs are
retrieved from the system's password database (the auxiliary group IDs are
reset in all other cases).
The actual authentication protocol uses environment variables and pipes to
communicate authentication information between modules. All of this
functionality is implemented by high level functions in the
libauthmod.a
library. This documentation is provided in the event
it is desired to put together a compatible authentication module without using
the code from libauthmod.a
.
The login process performs the following procedure prior to running the first authentication module:
1) The AUTHENTICATED
environment variable is cleared (set to
an empty string). argv[0]
is checked to make sure it contains a
full pathname, and its contents are used to set the AUTHUSER
environment variable. If AUTHUSER
is already set,
argv[0]
is ignored. If argv[0]
does not contain a
full pathname, AUTHUSER
must already be set prior to running this
process.
2) wait(2)
is repeatedly called to reap any zombie child
processes that are a byproduct of this authentication protocol.
wait(2)
is called repeatedly until there are no more child
processes left.
3) The AUTHARGC
environment variable is checked. If it is not
defined it means that the process was invoked for the first time, by a system
daemon process. If AUTHARGC
is defined it means that this is not
the first time this process was executed for this connection, and the previous
authentication request failed.
4) If necessary, AUTHARGC
is set to contain the decimal value
of argc, as received by main.
5) The environment variables ARGV0
, ARGV1
, up to
ARGVn
, are initialized to the contents of the argv array, as
received by main. ARGV0
is set to the contents of
argv[0]
, ARGV1
is set to the contents of
ARGV[2]
, and so on.
6) If the login process wants to have an expiration time for the login
attempt, then it should set the AUTHEXPIRE environment variable the first time
the login process is called. AUTHEXPIRE
should be set to the
calculated expiration time, based on the system clock. Subsequent invocations
(after failed authentication attempts) compare the system clock against the
contents of AUTHEXPIRE
to check if the login has expired. If not,
it's possible to calculate how much time is left, and set the alarm clock to
kill the process. The alarm clock is cleared if the next authentication
attempt is entered before the alarm clock goes off.
7) The login process then tries read a potential userid and password, in some sort of fashion, taking into account.
8) After obtaining the userid and password, the authentication user process kills the expiration timer (if it was set), and creates a pipe. It forks, and the parent process connects the output of the pipe to file descriptor 3, then executes the next process specified by the command line arguments. The child process writes the following text to the pipe:
service<NL>authtype<NL>authdata
service, authtype, and authdata, comprise the
authentication request, as defined previously. They are separated by a newline
character, <NL>
. A pipe is used to send the authentication
request to the authentication module instead of command line arguments or
environment variables. That's because you do not want the password readable by
anyone who happens to run ps(1)
at the same time. After writing
the authentication request to the pipe, the child process quickly
terminates.
An authentication module performs the following steps:
1) Checks the AUTHENTICATED
environment variable. If it is not
empty, it means that some previous authentication module successfully
authenticated the userid and the password, so the authentication module
immediately executes the next process specified by the command line.
Otherwise, the module reads the userid, password, and service from file
descriptor 3 which is immediately closed afterwards.
2) The authentication module calls wait(2)
repeatedly to reap
any zombie child processes.
3) Following that, the authentication module attempt to authenticate this request. There are three possible outcomes.
4) If the request is successfully authenticated, the module sets the
process's userid, groupid, then changes to the account's home directory. The
following environment variables are set: AUTHENTICATED
is set to
the userid; AUTHFULLNAME
is set to the user's "full name";
AUTHADDR
is set to the user's return address. After these
environment variables are set, the next process specified on the command line
is executed.
5) If the authentication request is rejected, the module process creates a pipe, forks, the parent process connects the output side of the pipe to file descriptor 3, then executes the next process specified by command line arguments line arguments. The child process writes the authentication request to the pipe, then immediately terminates. This allows the next authentication module, if present, to have the opportunity to authenticate this request.
6) In order to permanently reject the authentication request, without
invoking any additional authentication modules, the authentication module must
execute the process specified by the AUTHUSER
environment
variable. The command line arguments for the process must be taken from the
AUTHARGVn
series environment variables, the number of which is
given by the ARGC
environment variable.
An authenticated client process of this authentication library must take the following steps as the first order of business when it starts:
1) Repeatedly call wait(2)
to reap any zombie child
processes.
2) Verify that the AUTHENTICATED
environment variable is not
empty. If not, it means that none of the authentication modules successfully
authenticated this request, so the process specified by AUTHUSER
must be immediately invoked, with command line arguments set by the contents
of AUTHARGVn
series of environment variables.
3) Otherwise, the client process is considered to be authenticated, and ready for business.
File descriptor 3 is used in order to avoid messing with program's stdin, stdout, and stderr.