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:
setpwentsetpwent(3) library function. The handler is accessed
via the
auth_setpwent() function.setgrentsetgrent(3) library function. The handler is accessed
via the
auth_setgrent() function.endpwentendpwent(3) library function. The handler is accessed
via the
auth_endpwent() function.endgrentendgrent(3) library function. The handler is accessed
via the
auth_endgrent() function.getpwentgetpwent(3) library function. The handler is accessed
via the
auth_getpwent() function.getgrentgetgrent(3) library function. The handler is accessed
via the
auth_getgrent() function.getgroupsgetgroups(2)
system call. The handler is accessed via the
auth_getgroups() function.getpwnamgetpwnam(3) library function. The handler is accessed
via the
auth_getpwnam() function.getgrnamgetgrnam(3) library function. The handler is accessed
via the
auth_getgrpnam() function.getpwuidgetpwuid(3) library function. The handler is accessed
via the
auth_getpwuid() function.getgrgidgetgrgid(3) library function. The handler is accessed
via the
auth_getgrgid() function.authUSER and PASS FTP commands,
are passed via cmd_rec:
cmd->argv[0] = user-name
cmd->argv[1] = cleartext-password
The 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.
checkcmd_rec:
cmd->argv[0] = hashed-password
cmd->argv[1] = user-name
cmd->argv[2] = cleartext-password
The handler is accessed via the
auth_check()
function.uid_namecmd_rec:
cmd->argv[0] = (char *) uid
The handler is accessed via the
auth_uid_name() function.gid_namecmd_rec:
cmd->argv[0] = (char *) gid
The handler is accessed via the
auth_gid_name() function.name_uidcmd_rec:
cmd->argv[0] = user-name
The handler is accessed via the
auth_name_uid() function.name_gidcmd_rec:
cmd->argv[0] = group-name
The 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.