ProFTPD module mod_dbacl

The mod_dbacl module is used to map commands/requests to ACLs, and then to look up the ACLs/permissions for the path/file in question, on a per-command/request basis, from a SQL table. Thus the mod_dbacl module allows the use of SQL tables for controlling permissions of files, directories, etc on the server.

Installation instructions are discussed here.

The most current version of mod_dbacl can be found at:


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


2011-05-11: Thanks to Ben Timby <btimby at> for providing the path splitting idea and suggested lookup query.



Syntax: DBACLEngine on|off
Default: off
Context: server config, <VirtualHost>, <Global>
Module: mod_dbacl
Compatibility: 1.3.4rc3 and later

The DBACLEngine directive enables or disables the mod_dbacl module.


Syntax: DBACLPolicy "allow"|"deny"
Default: DBACLPolicy allow
Context: server config, <VirtualHost>, <Global>
Module: mod_dbacl
Compatibility: 1.3.4rc3 and later

The DBACLPolicy directive configures the default policy to use, when mod_dbacl is unable to retrieve the ACL setting from the SQL table, e.g. due to database misconfiguration or due to lack of database entries for the paths/ACLs in question.

The default DBACLPolicy setting of "allow" is highly recommended. You should only use "DBACLPolicy deny" if you need to have a "fail-closed" system of permissions on your server.


Syntax: DBACLSchema table [path-col read-col write-col delete-col create-col modify-col move-col view-col navigate-col]
Default: DBACLSchema ftpacl path read_acl write_acl delete_acl create_acl modify_acl move_acl view_acl navigate_acl
Context: server config, <VirtualHost>, <Global>
Module: mod_dbacl
Compatibility: 1.3.4rc3 and later

The DBACLSchema directive can be used to override the default SQL table and column names expected by the mod_dbacl module. More details on the SQL schema used by this module can be found in the usage section.


Syntax: DBACLWhereClause clause
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_dbacl
Compatibility: 1.3.4rc3 and later

The DBACLWhereClause directive configures an additional clause to add to the SQL WHERE clause constructed by mod_dbacl. The configured WHERE clause can be used to look up user/group-specific ACLs, for example.

Example WHERE clause of user-specific lookups:

  DBACLWhereClause "user = '%u'"
Note: If you use DBACLWhereClause, make sure that the columns named in the WHERE clause also have indexes on them, so that the SQL query can be executed more quickly.


To install mod_dbacl, copy the mod_dbacl.c file into the third-party module area in the proftpd source code:
  cp mod_dbacl.c proftpd-dir/contrib/
after unpacking the latest proftpd-1.3.x source code. For including mod_dbacl as a staticly linked module:
  ./configure --with-modules=mod_dbacl:mod_sql ...
Alternatively, mod_dbacl can be built as a DSO module:
  ./configure --enable-dso --with-shared=mod_dbacl ...
Then follow the usual steps:
  make install


Since the mod_dbacl module looks up ACLs/permissions from SQL tables, it requires that the mod_sql module (and a mod_sql module such as mod_sql_mysql, mod_sql_postgres, mod_sql_sqlite, etc) be used. For example, your configure command to build proftpd might look like:

  # ./configure --with-modules=mod_sql:mod_sql_sqlite:mod_dbacl ...

Mapping Commands/Requests to ACLs
The mod_dbacl works by first mapping each command/request to a specific ACL (i.e. a "permission group"), and then looking for the value for that ACL/path pair in the SQL table.

The ACLs currently supported by mod_dbacl, and the commands/requests for those ACLs, are:
 ACL   Commands 

Use the NAVIGATE ACL with caution. Many clients, both FTP and SFTP, will not function properly if they are unable to execute commands such as PWD or REALPATH. If you do use the NAVIGATE ACL, make sure that it restricts only very specific areas of your filesystem.

Splitting Paths into Component List
Once the command/request has been mapped to its ACL, the mod_dbacl looks at the path to the file/directory being requested by the client. Note that mod_dbacl always works on absolute paths; it resolves the path as sent by the client into the absolute path, regardless of any chroot(2) which may be in effect for the session.

The path-splitting algorithm takes a path like:

and breaks it down into a list of ever-more specific paths, like this:
Armed with this list, the mod_dbacl module can look for the closest-matching path in the SQL table, if any, which covers the path requested by the client.

This approach allows administrators to configure ACLs that cover broad ranges of filesystems (e.g. "/var") to very specific files, as they need.

Database Schema
So what does the database schema used by mod_dbacl look like? Here's an example SQLite script, which creates the table used by mod_dbacl, using the default table and column names:

  CREATE TABLE ftpacl (
    path TEXT NOT NULL,
    read_acl TEXT,
    write_acl TEXT,
    delete_acl TEXT,
    create_acl TEXT,
    modify_acl TEXT,
    move_acl TEXT,
    view_acl TEXT,
    navigate_acl TEXT

  CREATE INDEX ftpacl_path_idx ON ftpacl (path);
Note that creating an index on the ftpacl.path column is strongly recommended. Without an index on that column, your mod_dbacl lookups will be quite slow.

The string values which can appear in the ACL columns can be any of the following:

where "true"/"on" etc mean that the client has permission for that ACL/path combination, and "false"/"off" etc mean that the client does not have permssion, and mod_dbacl will deny that request.

Module Configuration

Configuring the mod_dbacl module is quite simple, as most of the configuration lies in the SQL tables. To enable mod_dbacl and use the default table/column names, simply use:

  <IfModule mod_dbacl.c>
    DBACLEngine on
That's it!

Example Command
To illustrate all of this, let's take a common FTP command and walk through how mod_dbacl would work. First, the FTP client (after authenticating) sends a RETR command to download a file:

  RETR dir/file.txt

The RETR command is mapped to its ACL, i.e. the "READ" ACL. Then the path is resolved to the absolute path, then split into a list, i.e.:


With the ACL and the path list, mod_dbacl builds up the SQL query to use:

  SELECT read_acl FROM ftpacl
    WHERE path IN ('/home',

In the ftpacl database table, assume the following rows are present:

  |  PATH                    |  READ_ACL             |
  | /home                    |  false                |
  | /home/user/dir           |  false                |
  | /home/user/dir/file.txt  |  true                 |
The longest matching path in the table is "/home/user/dir/file.txt", which matches the path being download by the FTP client. The value for the ftpacl.read_acl column is "true", thus mod_dbacl allows the command to proceed.

Note that mod_dbacl does not override any <Directory>/<Limit> sections which may also be configured, nor does it override the underlying filesystem permissions.

Rather than having its own separate log file, the mod_dbacl module uses the "dbacl" trace log channel in the TraceLog. Thus to enable logging for mod_dbacl, in order to debug configuration issues, you would use the following in your proftpd.conf:

  TraceLog /path/to/ftpd/trace.log
  Trace dbacl:20 ...

SFTP/SCP Interoperability
The mod_dbacl does work with the mod_sftp module such that SFTP requests are also handled/processed, just as FTP commands are handled. Note that SCP transfers may not work as expected with mod_dbacl yet (notably directory creation for recursive SCP uploads).

Author: $Author: tj $
Last Updated: $Date: 2011/05/11 17:50:24 $

© Copyright 2011 TJ Saunders
All Rights Reserved