ProFTPD module mod_conf_ldap

The mod_conf_ldap module can be used to store configuration information, as would normally be found in the proftpd.conf file, in LDAP directories, and to have proftpd consequently retrieve that configuration information. Detailed usage instructions can be found here.

This module is contained in the mod_conf_ldap.c file for ProFTPD 1.2.x, and is not compiled by default. Installation instructions are discussed here.

The most current version of mod_conf_ldap can be found at:


Please contact TJ Saunders <tj at> with any questions, concerns, or suggestions regarding this module.


After unpacking the latest proftpd-1.2 code (at least 1.2.10rc1), copy the mod_conf_ldap.c file into:
Then follow the normal steps for using third-party modules in proftpd:
  ./configure --with-modules=mod_conf_ldap
  make install


Conceptually, there are two basic elements in proftpd.conf: contexts and directives. Contexts include <Anonymous>, <VirtualHost>, the "server config" default context, and conditional contexts such as <IfDefine> and <IfModule>. Configuration directives are contained within a context.

To represent the configuration file contents within LDAP directories, a schema was designed that contains the necessary attrributes that represent these configuration contexts and directives.

LDAP Schema
The following LDAP schema (contained in the mod_conf_ldap.schema file bundled with mod_conf_ldap) defines the attributes and class needed to represent a proftpd.conf file in an LDAP directory:

  attributetype (
    NAME 'ProFTPDConfContains'
    DESC 'Ids for ProFTPDConfContexts contained within this context'
    EQUALITY caseExactMatch
    SUBSTR caseExactSubstringsMatch

  attributetype (
    NAME 'ProFTPDConfContext'
    DESC 'proftpd.conf start context string'
    EQUALITY caseExactMatch
    SUBSTR caseExactSubstringsMatch

  attributetype (
    NAME 'ProFTPDConfDirective'
    DESC 'proftpd.conf configuration directive'
    EQUALITY caseExactMatch
    SUBSTR caseExactSubstringsMatch

  attributetype (
    NAME 'ProFTPDConfId'
    DESC 'Descriptor for this proftpd.conf context'
    EQUALITY caseExactMatch
    SUBSTR caseExactSubstringsMatch

  objectclass (
    NAME 'ProFTPDConf'
    DESC 'proftpd.conf configuration context'
    MUST ( ProFTPDConfId $ ProFTPDConfContext )
    MAY ( ProFTPDConfContains $ ProFTPDConfDirective $ cn $ dc )
Each context is assigned a unique ID (ProFTPDConfId). Each ProFTPDConf class contains its unique ID and a context identifier (ProFTPDConfContext), and may contain multiple configuration directives (ProFTPDConfDirective) and multiple sub-contexts (ProFTPDConfContains). Contexts must be able to contain other contexts, which allows for nested contexts, such as:
  <Directory incoming>

Configuration URI
How does mod_conf_ldap do its magic? This module uses ProFTPD's FSIO API to temporarily redefine what it means to open and read a file; it presents a file-like interface to an LDAP directory such that ProFTPD's configuration parser does not know that the configuration is coming from a LDAP server rather than a flat file.

In order to accomplish this magic, mod_conf_ldap needs to know some things about the server, so that it can connect and retrieve the configuration data. This information is provided in the "path" to the configuration file, using proftpd's -c/--config command-line option. The specific "path" to use for mod_conf_ldap uses an URI-like syntax:

The syntax is long, but it has to be so in order to provide all of the information mod_conf_ldap needs. (This information cannot be stored in the configuration file because mod_conf_ldap will be constructing that configuration file.)

The "ldap://" (or "ldaps://") prefix informs the FSIO API that this "path" should be handled differently from a normal Unix filesystem path. The hostport is a host name, with an optional ":port", defines the LDAP server to contact. The dn is the base DN to use for search for configuration data. attrs is a comma-separated list of attributes to request; using "*" suffices. The scope should be "sub", to allow subtree searches. The filter is important: it is used to define a filter for searching for the root "server config" configuration context. Currently, mod_conf_ldap does not support any extensions.

Here is an example of using the above syntax:

  proftpd -c 'ldap:///dc=castaglia,dc=org?*?sub?(ProFTPDConfId=proftpdContext#0)'
Note that the LDAP URL is explicitly enclosed in single quotes, to present it from being handled by the shell. In this URL, the hostport is empty, which thus defaults to "localhost", port 389. Using "ldaps" as the scheme would connect to port 636 by default. The * wildcard is used to search for all attributes, and the sub parameter allows for subtree searching. The filter used identifies a ProFTPDConf object whose ProFTPDConfId is "proftpdContext#0". The filter must identify one and only one matching ProFTPDConf.

This URL path syntax can also be used as the parameter to the Include configuration directive:

    Include ldap:///dc=castaglia,dc=org?*?sub?(ProFTPDConfId=vhostContext#1)
This tells mod_conf_ldap to look for a ProFTPDConf object whose id is "vhostContext#1", and then to recurse through the contents of this "vhost" context.

The mod_conf_ldap module does not require the mod_ldap module to be compiled or configured.

Importing Existing Configurations
While storing configuration information in LDAP directories may make some tasks easier, it will making editing of configurations more complex. To help with this, mod_conf_ldap is accompanied by a Perl script that can be used to import existing proftpd.conf files into a directory.

The script reads a given proftpd.conf configuration file and generates an LDIF with the information from that file. One specifies the full path to the proftpd.conf to be imported. Use --help to see usage information.

Example: --dn=dc=castaglia,dc=org /etc/proftpd.conf > proftpd.ldif

Future Work
Future improvements to the mod_conf_ldap module wil include:

Author: $Author: tj $
Last Updated: $Date: 2004/08/01 23:17:13 $

© Copyright 2004 TJ Saunders
All Rights Reserved