Authentication Handlers
Strictly speaking, the authentication handlers are used for both
authentication (that is, verifying that a user is who she claims to be)
and authorization (determining what a user can and cannot do). A
password is often used for authentication; a user's UID and GID provide
"privileges" that are used for authorization. This combination
of functionality separates ProFTPD auth modules from PAM modules; PAM
modules are used for authentication only.
Authentication handlers allow a module to provide account information (password,
IDs, home directory, and shell) and UID/GID-to-name and name-to-UID/GID
mappings (used for directory listings). In order for a module to provide this
functionality, it must export an
authtable
(via the module structure), and define all of the
following handler names. Even if the module is not going to do
anything for a particular authentication function, it should define a handler,
so that a slot is properly reserved for the module.
Each handler accepts data via the cmd_rec
structure and should
return its data via the MODRET->data
member. The
mod_create_data()
function is usually used by an authentication handler to create and
populate this data structure properly, for return to the caller.
Defined authtable
handler names are:
setpwent
setpwent(3)
library function. The handler is accessed
via the
auth_setpwent()
function.setgrent
setgrent(3)
library function. The handler is accessed
via the
auth_setgrent()
function.endpwent
endpwent(3)
library function. The handler is accessed
via the
auth_endpwent()
function.endgrent
endgrent(3)
library function. The handler is accessed
via the
auth_endgrent()
function.getpwent
getpwent(3)
library function. The handler is accessed
via the
auth_getpwent()
function.getgrent
getgrent(3)
library function. The handler is accessed
via the
auth_getgrent()
function.getgroups
getgroups(2)
system call. The handler is accessed via the
auth_getgroups()
function.getpwnam
getpwnam(3)
library function. The handler is accessed
via the
auth_getpwnam()
function.getgrnam
getgrnam(3)
library function. The handler is accessed
via the
auth_getgrpnam()
function.getpwuid
getpwuid(3)
library function. The handler is accessed
via the
auth_getpwuid()
function.getgrgid
getgrgid(3)
library function. The handler is accessed
via the
auth_getgrgid()
function.auth
USER
and PASS
FTP commands,
are passed via cmd_rec
:
cmd->argv[0] = user-name cmd->argv[1] = cleartext-passwordThe handler is accessed via the
auth_authenticate()
function.auth
handler return, in case of a failed authentication
check, a value indicating the cause of the failure. The required
values are defined by the following macros:
PR_AUTH_AGEPWD
,
PR_AUTH_BADPWD
,
PR_AUTH_DISABLEDPWD
, and
PR_AUTH_NOPWD
.
check
cmd_rec
:
cmd->argv[0] = hashed-password cmd->argv[1] = user-name cmd->argv[2] = cleartext-passwordThe handler is accessed via the
auth_check()
function.uid_name
cmd_rec
:
cmd->argv[0] = (char *) uidThe handler is accessed via the
auth_uid_name()
function.gid_name
cmd_rec
:
cmd->argv[0] = (char *) gidThe handler is accessed via the
auth_gid_name()
function.name_uid
cmd_rec
:
cmd->argv[0] = user-nameThe handler is accessed via the
auth_name_uid()
function.name_gid
cmd_rec
:
cmd->argv[0] = group-nameThe handler is accessed via the
auth_name_gid()
function.
Use of the Authentication layer
An authentication module's handlers are used at various times during the
lifetime of the server:
getpwnam
handlers are called to resolve the User and
Group configuration directives
getpwnam
handlers are used to obtain account information
for the name following a USER
FTP command when a client is
logging in.
getgrent
handlers are used repeatedly to obtain a list of
supplemental groups for the user. (Note that currently this is
specific to mod_auth_unix
; other authentication modules may
use the getgroups
handler for retrieiving supplemental
group membership information.)
auth
handlers are invoked to authenticate a username and
cleartext password after a PASS
FTP command is received
from the client. A similar function to this is the check
handler, whose purpose is to support configuration directives such as
UserPassword
.
gid_name
and uid_name
handlers are used to
resolve IDs to names for legible directory listings.
Cascading Authentication Module Order
The cascaded order of authentication handlers is similar to that of command
handlers:
DECLINED
,
handlers in other modules are called in priority load order, just as with
command handlers. If all handlers for a particular function return
DECLINED
,
the core engine will assume that the operation failed.HANDLED
, the
core engine assumes that the operation completed successfully, and will
stop calling module authentication handlers. Most authentication
handlers must return data if they complete successfully. Note
that some void
-style handlers do not have this requirement;
ie setpwent
and friends.ERROR
, the core
engine assumes that an error has occured, and discontinues calling other
handlers. Some authentication handlers, auth
, for example,
should use the
ERROR_INT
macro
to return a numeric error code, such as one of the
PR_AUTH_
* macros in
include/modules.h, indicating the reason for failure.
In order for this cascading mechanism to function properly and as expected,
the authentication module author should provide handlers for all of
the auth slots. Failure to do so means that the authentication module
provides an incomplete authentication layer, and cascaded calls will appear
to "skip" the module without reason. At present,
mod_auth_pam
exhibits this behavior: it is an authentication
module, but provides no mechanisms for providing group information or IDs.
It solely provides auth
's "yes/no" answer.
This cascading structure also allows authentication modules the opportunity
to be impolite, as when the module implements *Authoritative
configuration directives. In general, I tend to discourage the use of such
*Authoritative
options. This design of the authentication
mechanism allows for several different authentication mechanisms to coexist
simultaneously, so that one could use /etc/passwd
, SQL tables, and
LDAP servers all at same time. The source which contains the information for
a given username is the module that responds with the requested information
first. Having an *Authoritative
module, which would return
ERROR
instead of DECLINED
from its authentication
handlers, breaks this layering model. The AuthOrder
directive
(available starting in 1.2.8rc1) lets one explicitly set the order in which
authentication modules are searched and was written specifically to address
this issue.