ProFTPD Developer's Guide: Authenticating users

ProFTPD Version 1.2

Table of Contents

ProFTPD's Authentication Process
When an FTP client connects to a proftpd server, it needs to authenticate itself, as per the FTP protocol. The clients send a USER command followed by a PASS command in most cases.

Upon receiving a USER command, proftpd will first check to see if the requested user is allowed to log in, based on any <Limit LOGIN> directives. Then it will check to see if the login is allowed by any configured MaxClients, MaxClientsPerHost, and MaxHostsPerUser directives. If these directives mean that the client connection cannot be accepted, any configured DisplayGoAway message is sent to the client.

When proftpd receives a PASS command, it will again check for configured MaxClients, MaxClientsPerHost, and MaxHostsPerUser limits. The first check, during the handling of the USER command, handles UserAliased usernames; this check handles real usernames. The actual work of authenticating the user then takes place (more on this below). If the authentication succeeds, any DisplayLogin and AccessGrantMsg messages are sent to the client. Otherwise, any AccessDenyMsg message is sent.

Authenticating the User
During authentication, the process handling the connection is running under the identity configured using the User and Group configuration directives. Only after successfully authenticating the user will the process assume the identity and privileges of that user. This process of authentication is handled by the _setup_environment() function, and involves quite a bit.

First, this function determines whether the login request is for an <Anonymous> server, or for a real user. Unknown users are rejected at this point. The determination of "known" user is done via the auth_getpwnam() dispatch function, an abstraction of the getpwnam(3) function. Modules that wish to supply their own authentication routines will need to provide all of the dispatched authentication functions mentioned here. This dispatch function "cascades" through each of the registered authentication modules of the server, asking each module in turn to authenticate the user until an error is encountered or until a module successfully returns the requested information. This design allows multiple authentication schemes to be present simultaneously.

The auth_getgroups() dispatch function is similarly used to request the supplemental group membership information, both group names and group IDs, from authentication modules. The list of obtained group IDs, if any, will subsequently be passed on to setgroups(2). At this point, I would like to point out a common error message pertaining to supplemental group membership:

"unable to set groups: Invalid argument"
This message will occur for one of two reasons: negative IDs for the user, or the user is a member of more than the maximum allowable number of groups (NGROUPS, NGROUPS_MAX, _SC_NGROUPS_MAX NGROUPS_MAX Max simultaneous groups to which one may belong )

Next, the function will check to see if the requested user is root; logging in as root requires that the RootLogin directive be explicitly set, as this is a very bad idea. If the requested user is a member of an AnonymousGroup group, then <Limit>ed logins are again checked for the user.

At this point, the given password is checked. If any UserPassword directives are set, then the configured password will be checked using auth_check() abstracted authentication handler. If not, then the auth_authenticate() handler will be called. Should user authentication fail, then groups-based authentication, using the given password as a group password and/or any GroupPassword configuration directives, will be attempted.

If the requested user has succeeded up to this point, the default directory in which to place the user, either their home directory or any applicable DefaultChdir directives, is retrieved. This path is checked for any applicable <Limit> directives. Next, after logging a wtmp or utmp log (unless configured not to), this function will check and apply any DefaultRoot configuration directives as needed. Last, the identity of the current process is changed to be that of the authenticated user.

At this point, unless authentication has failed at any point earlier, the authentication process is done. Any .ftpaccess files are parsed, the default transfer mode is set (configurable via the DefaultTransferMode directive), and scoreboard files updated.

Authentication is a complex process, and may fail at several points: if an authentication module encounters an error while authenticating, if the login is not for a valid user or is not a valid UserAlias, if the login is denied by an applicable <Limit LOGIN>, if the password given was incorrect or expired, if the account used is disabled, if the user's account includes an invalid shell, if the login name is listed in a /etc/ftpusers file and the server is configured to honour that file, etc.

Table of Contents

Author: $Author: castaglia $
Last Updated: $Date: 2003/01/02 17:39:33 $

© Copyright 2000-2003 TJ Saunders
All Rights Reserved