-
-
Notifications
You must be signed in to change notification settings - Fork 3
authpam.7
authlib - Courier Authentication Library
authpam command [ arg ... ]
authpwd command [ arg ... ]
authshadow command [ arg ... ]
authindi command [ arg ... ]
authcustom command [ arg ... ]
This library is used for two purposes:
1. Read an E-mail address that is supposed to be for a local account. Determine the local account's home directory, and system userid and groupid.
2. Read a login id and a password. If valid, determine the account's home directory, system userid, and groupid.
The term "authentication" is used in the following documentation to refer to either one of these two functions. The library contains several alternative authentication implementations, that may be selected at runtime.
authpam
authenticates using the system's PAM library (pluggable authentication
module). This is, essentially, a way to use existing PAM modules for
authentication functionality. Note, however, that the authenticated
account's home directory, userid and groupid are still read from the
/etc/passwd file, since PAM functionality is limited to validating
account passwords.
authpwd
authenticates from the /etc/passwd file.
authshadow
like authpwd except passwords are read from /etc/shadow.
authindi
authenticate against indimail's MySQL database
authcustom
this is a stub where custom authentication code can be added. This
authentication module is just a stub that doesn't really do anything.
It's purpose is to serve as a placeholder where custom authentication
code can be easily added.
This is a complete list of available authentication modules. The actual installed authentication modules are determined by the resources on the server. For example, the authpam authentication module will be installed only if the system provides PAM support libraries.
The rest of this documentation describes the internal protocol used by this authentication library. It is only of interest to developers who wish to extend the authentication library to support a custom authentication module, or a derived extension to an existing module.
The original implementation of this authentication library used small, self-contained, binary programs, named for their authentication module: authshadow, authpam, and others.
This section describes the authentication protocol for self-contained authentication modules. Although the default configuration no longer uses self-contained modules, the stand-alone protocol serves as a foundation for the protocol used by authentication modules as part of the authdaemond authentication process, or when they are linked directly with the application that uses this authentication library.
Here's the typical way that stand-alone authentication modules are used:
1. A list of authentication modules are read from a configuration file. Multiple authentication modules could be available, but not all of them are required in most situations.
2. The application executes the following command:
LOGIN AUTHMODULE1 AUTHMODULE2 ... APP
LOGIN is a full pathname to an application that reads the authentication information, such as the userid and a password. Arguments to LOGIN are full pathnames to each authentication module (if there are more than one), followed by a full pathname to the main application.
3. LOGIN reads the userid and password, then runs the program specified by its first argument, which is the first authentication module. The remaining arguments are passed to the new process. The mechanism by which the authentication information is passed to the authentication module is described later.
4. Each authentication module reads the authentication information, and determines if the previous authentication module succesfully processed the authentication request. If not, the module attempts to authenticate it itself. In any event, the module runs the next program specified by its first argument, and the remaining arguments are passed along to the next program. If any previous authentication module succesfully processed the authentication request, the next program is run immediately without any further processing.
5. Eventually, APP runs, APP reads the authentication information and determines whether any authentication module managed to succesfully process the authentication request. If so, APP runs normally. Otherwise, APP runs LOGIN with its original arguments in order to return an error message ("Password invalid", or something similar) and read the next authentication request.
Daisy-chaining authentication modules, in this fashion, makes it possible to have hybrid systems that use multiple authentication modules. Example: using authpam to authenticate system accounts, and authmysql to authentication virtual mailboxes without a corresponding system account.
Here's a more detailed description of the overall process:
The LOGIN process checks if the AUTHARGC environment variable is set. If not, this is the first time the LOGIN process comes up, and LOGIN displays the initial login prompt. Additionally, the command line arguments to LOGIN are literal copied to the AUTHARGC and AUTHARGVn environment variables. That is: the number of command line arguments is saved in AUTHARGC; the zeroth command line argument is saved in AUTHARGV0; the remaining command line arguments are saved in AUTHARGV1, AUTHARGV2, and so on.
After obtaining the authentication information (such as the userid and password), LOGIN creates a pipe, and arranges for the output end of the pipe to be located on file descriptor #3. The LOGIN process forks; the original process then executes the first authentication module, in the manner described earlier; the child process writes the authentication record to the pipe, then terminates.
The authentication record is a chunk of data in the following format:
SERVICE<NEWLINE>AUTHTYPE<NEWLINE>AUTHDATA
Each occurence of <NEWLINE> represents an ASCII linefeed character (#10). "SERVICE" identifies the service that originates the authentication request, such as "imap", or "webmail". Authentication module may use this identifier, or ignore it.
"AUTHTYPE" identifies the format of the authentication request. Everything after the second <NEWLINE> is an opaque blob of data, whose format is determined by AUTHTYPE.
Note: There's a theoretical upper limit on the maximum size of the authentication record. It is high enough not to matter in most situations (the total number of characters allowed cannot be more than 8189 characters on a typical GNU/Linux system).
The following AUTHTYPE formats are currently defined:
login
A typical userid/password authentication request. AUTHDATA contains the
following data: userid<NEWLINE>password<NEWLINE>.
cram-md5
Specifies the CRAM-MD5 authentication request. AUTHDATA contains the
following data: challenge<NEWLINE>response<NEWLINE>. The
"challenge" and "response" strings are base64-encoded.
cram-sha1
Specifies the CRAM-SHA1 authentication request, instead of CRAM-MD5, and
uses the same format for AUTHDATA.
The first thing an authentication module does is check if the environment variable AUTHENTICATED is set to a non-empty string. If so, it means that a previous authentication module has handled the authentication request, so this module simply runs the next program, specified by the first argument to this authentication module.
Otherwise, the authentication module reads the authentication record from file descriptor #3, and determines whether it wants to try this authentication record. If not, the module creates a new pipe, arranges the output of the pipe to be on file descriptor #3, forks, the parent process runs the next authentication module, and the child process writes the authentication record to the pipe, then exits.
There are two ways to handle an authentication request: 1) Use the AUTHARGC and AUTHARGVn variables to restart the entire authentication process - this is used in the event it is determined that the authentication request must be failed, or 2) run the next daisy-changed module, in the manner described previously, when it is determined that another authentication module can attempt to try to handle this request.
The following action occurs when the authentication module succesfully validates an authentication request:
1. The authenticated login ID is saved in the AUTHENTICATED environment variable.
2. The process's userid and groupid are reset to the corresponding userid and groupid of the authenticated login id, and the current directory is set to the process's defined home directory.
3. Some additional environment variables may also be initialized: AUTHFULLNAME - the login ID's full name; MAILDIR - the login ID's default maildir mailbox; MAILDIRQUOTA - the requested maildir quota.
Eventually, APP runs. The process closes file descriptor #3 (if it's open, and ignores the error if file descriptor #3 does not exist). If the AUTHENTICATED environment variable is set, it must mean that an authentication module was able to handle this authentication request, so APP starts up and runs normally. Otherwise the original command is reconstructed from the AUTHARGC and AUTHARGVn variables, and the initial login process runs again.
This authentication library provides several convenient functions which can be used to quickly create a compliant login process, and its corresponding application. The login process should be structured as follows:
int main(int argc, char **argv)
{
if (authmoduser(argc, argv, TIMEOUT, ERR_TIMEOUT))
{
/* Print initial greeting here */
}
else
{
/* Error: invalid userid/password */
}
/* read userid and password */
authmod(argc-1, argv+1, SERVICE, AUTHTYPE, AUTHDATA);
}
The authmoduser function takes care of copying the command line parameters to their corresponding environment variables, and checking whether or not this is the initial time this process runs, or if it is running again after a failed authentication process. TIMEOUT specifies the absolute login timeout, authmoduser quietly terminates the process if it runs due to a failed authentication request and at least TIMEOUT seconds have elapsed since the first time authmoduser was run. ERR_TIMEOUT specifies the number of seconds that authmoduser will sleep after a failed authentication request.
The SERVICE, AUTHTYPE, and AUTHDATA arguments to authmod are null-terminated character strings that form the authentication request. authmod takes care of setting up the pipe to the first authentication module, and runs it.
The application process is even simpler:
int main(int argc, char **argv)
{
const char *loginid=authmodclient();
/* Application begins normally */
}
The authmodclient function returns the authenticated login ID. If the authentication request failed, authmodclient reruns the original login process, and doesn't return.
An authentication module needs to define the following structure:
struct authstaticinfo {
const char *auth_name;
char * (*auth_func)(const char *, const char *, char *, int,
void (*)(struct authinfo *, void *),
void *);
int (*auth_prefunc)(const char *, const char *,
int (*)(struct authinfo *, void *),
void *);
void (*auth_cleanupfunc)();
int (*auth_changepwd)(const char *, /* service */
const char *, /* userid */
const char *, /* oldpassword */
const char *); /* new password */
} ;
auth_func points to a function that handles the authentication request. If succesful, auth_func is responsible for resetting the userid and groupid, changing to the authentication account's home directory, and setting up the necessary environment variables. The first three arguments to auth_func will be SERVICE, AUTHTYPE, and AUTHDATA. The next argument is a boolean flag which is non-zero if the authentication code is being called in the context of a stand-alone authentication module, or zero if the authentication code is called directly by an application. The fifth argument points is a callback function pointer, which may be NULL. If it's not null, auth_func should not reset the userid, groupid, or the home directory of this process, but should instead initialize the authinfo structure, which is defined as follows:
struct authinfo {
const char *sysusername;
const uid_t *sysuserid;
gid_t sysgroupid;
const char *homedir;
const char *address; /* The E-mail address */
const char *fullname; /* gecos, etc... */
const char *maildir;
const char *quota;
const char *passwd;
const char *clearpasswd; /* For authldap */
unsigned staticindex; /* When statically-linked functions are
** called, this holds the index of the
** authentication module in authstaticlist */
} ;
The passwd, clearpasswd, and staticindex fields are not used by auth_func. Either sysusername or sysuserid must be a non-NULL pointer. sysuserid specifies an explicit userid, otherwise sysusername is looked up in the password file.
The last argument to auth_func is an opaque pointer that gets passed as the second argument to the callback function.
auth_func should return a pointer to the authenticated loginid, in dynamic memory (the memory should be **free()**ed after user. A NULL return indicates an authentication failure. The authentication module should set errno to EPERM in the event that it the next authentication module should have a chance to process the authentication request, or use any other errno value to immediately fail the authentication request, and rerun the original login process.
The auth_prefunc, auth_cleanupfunc, and auth_changepwd functions are not used by stand-alone modules, but when the authentication module is directly linked with an application.
auth_prefunc verifies that the requested userid exists. No passwords are validated, the first two arguments to auth_prefunc are the userid, and SERVICE. auth_prefunc should initialize an authinfo structure, and run the callback function, the third argument to auth_prefunc. The callback function receives the fourth argument to auth_prefunc as an opaque pointer.
auth_prefunc should come back with the callback function's return code, if the requested userid was found. Otherwise, auth_prefunc should return a non-zero integer. A positive integer should be return in the event that this authentication request should be stopped, and a negative itneger if another authentication module can be tried. An application that links against this authentication library will run each configured authentication module's auth_prefunc, until some module is able to process the requested userid, or until auth_prefunc comes back with a non-zero positive return code.
auth_func or auth_prefunc might allocate some internal resources, which should be freed by calling auth_cleanupfunc.
The auth_changepwd function is called to implement the change password functionality.
This authentication library contains several functions and macros that can be helpful in building authentication modules.
#define MODULE auth_func
#include "mod.h"
mod.h contains template code that reads an authentication request from the previous authentication module, call auth_func, in such a manner, and appropriately run the next module in the authentication chain.
The auth.h header file also declares several useful functions that authentication-related code may find convenient.
- /etc/indimail/authmodulelist* - list of authentication modules read by applications that directly link with authlib
IndiMail(7)