ProFTPD Application Programmer Interface
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

NOTE: This API documentation ONLY applies to proftpd versions 1.1.5 and
greater, wherein the module interface was significantly enhanced.

ProFTPD modules are designed to handle and respond to configuration
directives (at startup), FTP commands sent over the control connection by
FTP clients, and authentication requests.

Module are prioritized in the *inverse* order of which they were loaded.
In other words, the last loaded module is the FIRST to receive calls for a
particular configuration directive, ftp command or authentication request.
This can be used to allow later loaded modules (higher priority) to
(optionally) "override" lower priority modules.  Thus, load order of the
modules can be VERY important.

Module handler functions are _always_ declared as:

MODRET	my_handler_func(cmd_rec *cmd);

In include/modules.h, MODRET is defined as 'static modret_t *'.  cmd_rec
is a structure created by the engine and passed to the handler which
contains all information regarding the command, etc.  modret_t is a
special structure that is created by the handler and returned to the
engine in order to tell the engine how to proceed.  There are a few macros
in include/modules.h which allow the module programmer to easily create
return structures.  The `cmd' argument to each macro is a pointer to
the current module function's cmd_rec structure.

HANDLED(cmd)
 - indicates that the handler properly handled the command, and that the
engine should consider the command completed and continue processing.
Note that if a module handler returns HANDLED, POST_CMD handlers
will be called for the command (see below for handler types).

DECLINED(cmd)
 - indicates that the engine should act as though the handler was never
called and continue processing.  POST_CMD type handlers will NOT
be called in this case.

ERROR(cmd)
 - A protocol error occured.  POST_CMD type handlers are NOT
called.

ERROR_MSG(cmd,numeric,message)
 - Same as above, however the string composed of "numeric message" is sent
to the client.  In the case of directive configuration handlers, the
"numeric" argument is ignored, "message" is displayed to the user (or
logged via syslog), and proftpd terminates.

ERROR_INT(cmd,n)
 - Same as above, however this indicates a single integer numeric error.
(Used only in authentication/mapping handlers [see mod_unixpw.c])

Handler Tables
--------------

Each module can define up to three different handler tables (which are
registered via the module structure).  These need not all be supplied.
They are grouped by handler class:

  conftable[]:	For configuration directive handlers.
  cmdtable[]:	For command handlers, including POST_CMD and PRE_CMD
                (see below)
  authtable[]:	For authentication handlers.

The "conftable" is a structure which lists all configuration directive
handlers for the module.

The "cmdtable" is a structure which lists all FTP command handlers for the
module.  Each entry in this table contains a special "command type" field
which determines the general 'type' of handler.  There are currently four
types: CMD, PRE_CMD, and POST_CMD and LOG_CMD.  When proftpd receives a
command for a client, it enters a five (eight?) step command->module
cascading delivery process: 

  1. Call any PRE_CMD type handlers which match the special "*"
      command wildcard
  1a. Call any PRE_CMD type handlers which match the command.
  2. Call any CMD type handlers which match the special "*"
      command wildcard
  2a. Call any CMD type handlers which match the command.
  3. Call any POST_CMD type handlers which match the special "*"
      command wildcard
  3a. Call any POST_CMD type handlers which match the command.
  4. Call any LOG_CMD type handlers which match the special "*" wildcard.
  5. Call any LOG_CMD type handlers which match the command.

Further more, the return type of a particular command can allow or
disallow further dispatching.  Rules:

  PRE_CMD:
    1. If DECLINED is returned, all other PRE_CMD handlers are called.
    2. If ERROR is returned, command handler dispatching stops completely.
  CMD:
    1. If DECLINED is returned, all other CMD handlers are called.
    2. If ERROR is returned, command handler dispatching stops completely.
  POST_CMD:
    1. If ERROR is returned, the message (if any) is sent to syslog,
       however because the CMD handler already executed, nothing further
       can be done.
    
As you can no doubt see, this allows a higher priority module to
"overload" a PRE_CMD handler for a particular command and allow/disallow
the command as desired.

As a general rule of thumb, PRE_CMD handlers should check syntax/basic
applicability of the command, while CMD type handlers should actually
do the 'work'.  POST_CMD handlers generally handle any kind of cleanup,
while LOG_CMD handlers handle logging successful completion of the
command.

Responding to client requests in command handlers
=================================================

There are two main ways to respond to a client command inside a command
handler.  The first way is incompatible with other other handlers, and
should only be used if the handler is about to terminate the current
connection (and thus kill the child, usually with end_login()).  This
first method, using one of the core functions outlined below, must be used
because in the event that a handler is about to terminate proftpd, the
internal response lists will never be processed by the proftpd engine.

  Method 1 (Use only in conjunction with end_login() or similar
            termination)

    send_response(char *numeric, char *format, ...);
      -- immediately sends the given response with the indicated numeric
         to the client

    send_response_ml_start(char *numeric, char *format, ...);
      -- starts a multiline ftp protocol with the given numeric

    send_response_ml(char *format, ...);
      -- continues a multiline response using the numeric specified
         in send_response_ml_start();

    send_response_ml_end(char *format, ...);
      -- completes a multiline response

    send_response_async(char *numeric, char *format, ...);
      -- send an asyncronous message to the client, this function is
         suitable for use inside signal handlers

The second, and prefered, method of transmitting numeric + text message
responses to clients is via the internal response chain.  Using this
allows all handlers to add their own individual responses which will all
be sent en masse after the command successfully completes (or fails).

Proftpd maintains two such chains, one response chain for success
messages, and one for error messages.  However, when all handlers for a
given command have been called, proftpd evaluates the final condition of
the command.  If it has failed (caused by a handler returning one of the
available ERROR* macros), all responses pending in the error response
chain are sent.  If the command has successfully completed, the normal
(success) response chain is sent.  If a command has neither completed
successfully nor resulted in an error, proftpd assumes the command is
invalid and informs the client appropriately.  Either way, once the
"lifetime" of the command is over, and one (or none) of the response
chains has been sent, BOTH chains are destroyed.

  Method 2 (using response chains)

    add_response(char *numeric, char *format, ...);
      -- adds the given numeric + message to the end of the _success_
         chain, to be sent if the command successfully completes.

    add_response_err(char *numeric, char *format, ...);
      -- adds the given numeric + message to the end of the _error_
         chain, to be sent if the command results in a final error.

As you can see, with method 2, there is no corresponding _ml* functions
for multiline replies.  This is because proftpd automatically generates a
multiline format reply if it detects that there are two or more responses
with the same numeric waiting to be sent to the client.  In many cases,
you may be writing a handler (post_cmd, for example) that neither cares
nor specifically knows what numerics other handlers are using during their
responses.  In this case, you can use the special R_DUP response numeric,
which tells proftpd that your response should be _assumed_ to be part of a
multiline response started by another handler.  For example, if the
following add_response() calls were made from different modules:

module a:
  add_response(R_200,"Command successfully completed.");

module b:
  add_response(R_DUP,"Statistics for command '%s': none.",cmd->argv[0]);

module c:
  add_response(R_DUP,"XFOO post_cmd handler ran.");

The final output sent to the client (assuming the command was successfully
handled) would be (assuming your command is named 'XFOO'):

200-Command successfully completed.
 Statistics for command 'XFOO': none.
200 XFOO post_cmd handler ran.

Authentication Handlers
=======================

Authentication handlers allow a module to provide (or overload)
authentication, uid/gid to name and name to uid/gid mappings.

In order for a module to provide this functionality, it must export an
authtable (via the module structure), and define one or more of the
following handler "names" (authtable.name).

Each handler accepts data in the cmd structure and should return it's
data in the modret->data field.  The core function mod_create_data()
can create this data structure properly for return to the caller.

Defined 'names' are:

"setpwent"	: low-level emulation of setpwent libc function
"setgrent"	: low-level emulation of setgrent libc function
"endpwent"	: low-level emulation of endpwent libc function
"endgrent"	: low-level emulation of endgrent libc function
"getpwent"	: low-level emulation of getpwent libc function
"getgrent"	: low-level emulation of getgrent libc function
"getpwnam"	: low-level emulation of getpwnam libc function
"getgrnam"	: low-level emulation of getgrnam libc function
"getpwuid"	: low-level emulation of getpwuid libc function
"getgrgid"	: low-level emulation of getgrgid libc function
"auth"		: authenticate user
                  (cmd->argv[0] = user,
                   cmd->argv[1] = cleartext password)
"check"		: compare supplied passwords
		  (cmd->argv[0] = hashed password,
                   cmd->argv[1] = user,
		   cmd->argv[2] = cleartext password)
"uid_name"	: map uid to name
		  (cmd->argv[0] = (char*)uid)
"gid_name"	: map gid to group
                  (cmd->argv[0] = (char*)gid)
"name_uid"      : map name to uid
                  (cmd->argv[0] = name)
"name_gid"      : map group to gid
                  (cmd->argv[0] = name)

The cascaded order of authentication handlers is similar to command
handlers, but slightly different.  Rules:

  1. If an authentication handler returns 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, proftpd will assume that the operation failed.

  2. If an authentication handler returns HANDLED, proftpd assumes
     that the operation completed successfully, and will stop calling
     auth handlers.  Most auth handlers MUST return data if they complete
     successfully (note that some void-style handlers do not have this
     requirement; i.e. "setpwent" and friends).

  3. If an authentication handler returns ERROR, proftpd assumes an
     error has occured and discontinues calling other handlers.  Some
     functions ("auth", for example), should use the ERROR_INT macro
     to return a numeric error code (one of the AUTH_* macros in
     include/modules.h) indicating the reason for failure.
