ProFTPD module mod_ldap

## ProFTPD module `mod_ldap`

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

The most current version of `mod_ldap` is distributed with the ProFTPD source code.

## Author

Please contact John Morrissey <jwm at horde.net> with any questions, concerns, or suggestions regarding this module.

## Directives

- LDAPAliasDereference
- LDAPAttr
- LDAPAuthBinds
- LDAPBindDN
- LDAPDefaultAuthScheme
- LDAPDefaultGID
- LDAPDefaultQuota
- LDAPDefaultUID
- LDAPForceDefaultGID
- LDAPForceDefaultUID
- LDAPForceGeneratedHomedir
- LDAPGenerateHomedir
- LDAPGenerateHomedirPrefix
- LDAPGenerateHomedirPrefixNoUsername
- LDAPGroups
- LDAPLog
- LDAPProtocolVersion
- LDAPQueryTimeout
- LDAPSearchScope
- LDAPServer
- LDAPUsers
- LDAPUseTLS

### LDAPAliasDereference

Syntax: LDAPAliasDereference never|always|search|find
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

The `LDAPAliasDereference` directive configures how aliases are handled. The possible values have the following behaviors:

- never

  Never dereference aliases

- always

  Always dereference aliases

- search

  Dereference aliases only when searching

- find

  Dereference aliases only when locating the base object for the search

The default is "never", e.g.:

      <IfModule mod_ldap.c>
        LDAPAliasDeference never
      </IfModule>

### LDAPAttr

Syntax: LDAPAttr old-attr-name new-attr-name
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

The `LDAPAttr` directive is used to map, or to associate, a standard attribute name to a non-standard attribute name. If, for example, your LDAP directory schema used different names for some of the attributes used by `mod_ldap`, you would use this directive to tell `mod_ldap` what new attribute names to use.

The following LDAP attributes can be renamed in this manner:

- `uid`
- `uidNumber`
- `gidNumber`
- `homeDirectory`
- `userPassword`
- `loginShell`
- `cn`
- `memberUid`
- `ftpQuota`

### LDAPAuthBinds

Syntax: LDAPAuthBinds on|off
Default: LDAPAuthBinds on
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

By default, the DN specified by the `LDAPBindDN` will be used to bind to the LDAP server to obtain user information, including the `userPassword` attribute. If `LDAPAuthBinds` is set to on, the DN specified by `LDAPDNInfo` will be used to fetch all user information except the `userPassword` attribute. Then, the `mod_ldap` module will bind to the LDAP server as the user who is logging in via FTP with the user-supplied password. If this bind succeeds, the user is considered authenticated and is allowed to log in. This method of LDAP authentication has the added benefit of supporting any password encryption scheme that your LDAP server supports.

In versions of `mod_ldap` up to 2.7.6, the default for `LDAPAuthBinds` was off. After `mod_ldap` 2.8, the default value for `LDAPAuthBinds` is on.

### LDAPBindDN

Syntax: LDAPBindDN dn password
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.3.5rc1 and later

The `LDAPBindDN` directive configures the DN and the password that `mod_ldap` will use when binding to the LDAP directory. If this configuration directive is missing, then anonymous binds are used.

The default is:

      <IfModule mod_ldap.c>
        # Use anonymous binds
        LDAPBindDN "" ""
      </IfModule>

See also: `LDAPServer`

### LDAPDefaultAuthScheme

Syntax: LDAPDefaultAuthScheme crypt|clear
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

The `LDAPDefaultAuthScheme` directive specifies the authentication scheme used for passwords which have no "{hashname}" prefix in the LDAP directory. For example, if you are:

      userPassword mypass

in your directory, you would want to set `LDAPDefaultAuthScheme` to clear.

The default value is crypt.

### LDAPDefaultGID

Syntax: LDAPDefaultGID gid
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

The `LDAPDefaultGID` directive sets the default GID to be used for users when no `gidNumber` attribute is found for that user.

This directive is useful primarily in virtual user environments common in large-scale ISPs and hosting organizations. If a user does not have an LDAP `gidNumber` attribute, the `LDAPDefaultGID` is used. This allows one to have a large number of users in an LDAP directory without `gidNumber` attributes; setting this configuration directive will automatically assign those users a single GID.

See also: `LDAPDefaultUID`

### LDAPDefaultQuota

Syntax: LDAPDefaultQuota default-quota
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.3.5rc1 and later

The `LDAPDefaultQuota` directive configures a default-quota to use if a user does not have an `ftpQuota` attribute. This parameter is formatted the same way as the `ftpQuota` LDAP attribute.

### LDAPDefaultUID

Syntax: LDAPDefaultUID uid
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

The `LDAPDefaultUID` directive sets the default UID to be used for users when no `uidNumber` attribute is found for that user.

This directive is useful primarily in virtual user environments common in large-scale ISPs and hosting organizations. If a user does not have an LDAP `uidNumber` attribute, the `LDAPDefaultGID` is used. This allows one to have a large number of users in an LDAP directory without `uidNumber` attributes; setting this configuration directive will automatically assign those users a single UID.

See also: `LDAPDefaultGID` DoAuth

By default, the search filter template used is:

      (&(uid=%v)(objectclass=posixAccount))

The uid for the the search filter is taken from the `LDAPAttr` directive. Search filter templates are only supported in versions of `mod_ldap` 2.7 and later.

See also: `LDAPAttr`

### LDAPForceDefaultGID

Syntax: LDAPForceDefaultGID on|off
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

Even when a `LDAPDefaultGID` is configured, the `mod_ldap` module will allow individual users to have `gidNumber` attributes that will override this default GID. With `LDAPForceDefaultGID` directive configured to be on, all LDAP-authenticated users are given the default GID; GIDs may not be overridden by `gidNumber` attributes.

### LDAPForceDefaultUID

Syntax: LDAPForceDefaultUID on|off
Default: None
Context: server config
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

Even when a `LDAPDefaultUID` is configured, the `mod_ldap` module will allow individual users to have `uidNumber` attributes that will override this default UID. With `LDAPForceDefaultUID` directive configured to be on, all LDAP-authenticated users are given the default UID; UIDs may not be overridden by `uidNumber` attributes.

### LDAPForceGeneratedHomedir

Syntax: LDAPForceGeneratedHomedir off|on
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

When no `homeDirectory` attribute is found, the `mod_ldap` module can be configured to generate a home directory using the `LDAPGenerateHomedir` directive. If there is a `homeDirectory` attribute present, however, the `mod_ldap` module will use that attribute value as the home directory.

However, there may be cases where the administrator wishes to override the `homeDirectory` attribute, and thus to always use the home directory value that `mod_ldap` would generate. The `LDAPForceGeneratedHomedir` directive is used in such cases.

For example, assume that the user logging in is named "tj", and has an LDAP object whose `homeDirectory` attribute value is "/home/tj". To force the use of `mod_ldap`'s generated home directory instead of that `homeDirectory` value, the configuration might look like:

      LDAPForceGeneratedHomedir on
      LDAPGenerateHomedir on
      LDAPGenerateHomedirPrefix /var/ftp

Using the above configuration, the home directory that the `mod_ldap` module would use is `/var/ftp/tj`, despite what `homeDirectory` attribute may be in the LDAP directory.

Note that if `LDAPForceGeneratedHomedir` is enabled, then `LDAPGenerateHomedir` must also be enabled. It is an error to enable `LDAPForceGeneratedHomedir` without also enabling `LDAPGenerateHomdir`.

See also: `LDAPGenerateHomedir`, `LDAPGenerateHomedirPrefix`, `LDAPGenerateHomedirPrefixNoUsername`

### LDAPGenerateHomedir

Syntax: LDAPGenerateHomedir on|off
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

By default, the `mod_ldap` module uses the `homeDirectory` attribute to determine what home directory to use for the session. Sometimes, however, an administrator will want to use a different home directory for these FTP/SFTP sessions, something other than the path in the `homeDirectory` attribute. The `LDAPGenerateHomedir` directive is used for situations like this.

The `LDAPGenerateHomedir` directive configures the `mod_ldap` module to "generate" a new home directory value, overriding the value from the `homeDirectory` attribute. The generated home directory value requires that a starting point for the new home directory, a "prefix", also be provided using the `LDAPGenerateHomedirPrefix` directive.

The `LDAPGenerateHomedir` directives does not cause the new home directory to be created on the filesystem. It only changes the home directory value that the `mod_ldap` module provides to the ProFTPD engine. The creation of the home directory, if it does not already exist, is done using the `CreateHome` directive.

See also: `LDAPGenerateHomedirPrefix`, `LDAPGenerateHomedirPrefixNoUsername`

### LDAPGenerateHomedirPrefix

Syntax: LDAPGenerateHomedirPrefix prefix
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

The `LDAPGenerateHomedirPrefix` directive is used when `LDAPGenerateHomedir` is enabled, causing the `mod_ldap` module to generate a default home directory, when the `homeDirectory` attribute value is not present. The generated home directory value like this:

      prefix/username

The configured prefix string has the username (from the `uid` attribute) appended to generate the home directory value for the user.

For example:

      LDAPGenerateHomedir on
      LDAPGenerateHomedirPrefix /var/ftp

Using the above configuration, and assuming a user name of "tj", the home directory that the `mod_ldap` module would use is `/var/ftp/tj`, no matter what the `homeDirectory` attribute may be in the LDAP directory.

See also: `LDAPForceGeneratedHomedir`, `LDAPGenerateHomedir`, `LDAPGenerateHomedirPrefixNoUsername`

### LDAPGenerateHomedirPrefixNoUsername

Syntax: LDAPGenerateHomedirPrefixNoUsername on|off
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

When the `LDAPGenerateHomedir` and `LDAPGenerateHomedirPrefix` directives are used, the generated home directory value for the session is:

      prefix/username

However, there may be cases where the administrator does not want the username automatically appended to the generated value, and instead wishes to use just the prefix as the home directory. For these use cases, use the `LDAPGenerateHomedirPrefixNoUsername` directive.

For example:

      LDAPGenerateHomedir on
      LDAPGenerateHomedirPrefix /var/ftp
      LDAPGenerateHomedirPrefixNoUsername on

Using the above configuration, and assuming a user name of "tj", the home directory that the `mod_ldap` module would use is `/var/ftp`, no matter what the `homeDirectory` attribute may be in the LDAP directory.

See also: `LDAPGenerateHomedir`, `LDAPGenerateHomedirPrefix`

### LDAPGroups

Syntax: LDAPGroups base-dn cn-filter-template gid-number-filter-template member-uid-filter-template
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.3.5rc1 and later

The `LDAPGroups` directive activates LDAP GID-to-name lookups for directory listings. The first parameter to this directive is the LDAP base DN to use for GID-to-name lookups. The second through fourth optional parameters are templates to be used for the search filter; `%v` will be replaced with the GID that is being looked up.

By default, the CN filter template look like this:

      (&(LDAPAttr_cn=%v)(objectclass=posixGroup))

The `gidNumber` filter template is:

      (&(LDAPAttr_gidNumber=%v)(objectclass=posixGroup))

and the `memberUid` filter template used is:

      (&(LDAPAttr_memberUid=%v)(objectclass=posixGroup))

Note that filter templates are only supported in `mod_ldap` version 2.8.3 and later.

The attribute names used in the default search filters are taken from the `LDAPAttr` directive.

### LDAPLog

Syntax: LDAPLog file|"none"
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.3.5rc4 and later

The `LDAPLog` directive is used to specify a log file for `mod_ldap`'s reporting on a per-server basis. The file parameter given must be the full path to the file to use for logging.

Note that this path must not be to a world-writable directory and, unless `AllowLogSymlinks` is explicitly set to on (generally a bad idea), the path must not be a symbolic link.

### LDAPProtocolVersion

Syntax: LDAPProtocolVersion 2|3
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

The `LDAPProtocolVersion` directive configures the version of the LDAP protocol that `mod_ldap` will use when talking to the LDAP servers. The default protocol version used is 3.

### LDAPQueryTimeout

Syntax: LDAPQueryTimeout secs
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

The `LDAPQueryTimeout` directive configures the timeout value, in seconds, that will be used for LDAP directory queries. The default timeout value is determined by your LDAP API.

### LDAPSearchScope

Syntax: LDAPSearchScope base|onelevel|subtree
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

The `LDAPSearchScope` directive is used to set the scope used for LDAP searches. The default setting, subtree, searches for all entries in the tree from the current level down. Setting this directive to onelevel searches only one level deep in the LDAP tree.

Note that the `LDAPSearchScope` directive cannot be used when the LDAP URL syntax, rather than hostname/port, is used for your `LDAPServer` configuration. Why not? The search scope can be specified as part of the URL itself. This, combined with the fact that the `LDAPServer` directive can take multiple hosts/URLs, makes it clear to include the search scope in the URLs as needed.

If you are not using the LDAP URL syntax, then the following will use the subtree search scope:

      LDAPServer ldap.example.com

or, to make it explicit in your configuration:

      LDAPServer ldap.example.com
      LDAPSearchScope subtree

On the other hand, if you are using LDAP URLs, then you specify the search scope as part of the URL:

      LDAPServer ldap://ldap.example.com/??sub

It is important that the "/" after the hostname/port be part of your LDAP URL when specifying the search scope. That is, using:

      LDAPServer ldap://ldap.example.com??sub

will not work as expected; see RFC 2255, Section 3. LDAP URL parameters are not like HTTP URL query parameters; LDAP URL parameters are order-specific. And the "/" before any of the optional parameters is required.

### LDAPServer

Syntax: LDAPServer "url1|host1:port1 url2|host2:port2"
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

The `LDAPServer` directive allows you to to specify the hostname(s) and port(s) of the LDAP server(s) to use for LDAP authentication. If no `LDAPServer` configuration directive is present, the default LDAP servers specified by your LDAP library will be used. Note that the LDAP URL syntax may also be used.

To specify multiple LDAP servers, enclose the entire list of servers in quotation marks. For example:

      LDAPServer "host1:port1 host2:port2"

or:

      LDAPServer "url1 url2"

Th default search scope for LDAP URLs is "base" (unless a scope is explicitly provided in the URL). This behavior differs from the `LDAPSearchScope` directive, which defaults to "subtree".

Note that to use LDAPS (LDAP over SSL), use the URL format, e.g.:

      LDAPServer ldaps://host1:port1 ldaps://host2:port2

Alternatively, you can use the `LDAPUseTLS` directive, e.g.:

      LDAPServer ldap://host1:port1 ldap://host2:port2
      LDAPUseTLS on

to tell `mod_ldap` to use LDAP's STARTTLS mechanism.

### LDAPUsers

Syntax: LDAPUsers base-dn [name-filter-template [uid-filter-template]]
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.3.5rc1 and later

The `LDAPUsers` directive activates LDAP UID-to-name lookups for directory listings. The first parameter to this directive is the LDAP base DN to use for UID-to-name lookups. The optional second parameter is a template to be used for the search filter for the username; `%v` will be replaced with the UID that is being looked up. Similarly, an optional third parameter is also a template, to be used for the search filter for the UID.

By default, the name search filter template looks like this:

      (&(uid=%v)(objectclass=posixAccount))

and the UID search filter template looks like this:

      (&(LDAPAttr_uidNumber=%v)(objectclass=posixGroup))

The uidNumber attribute name used in the search filter comes from the `LDAPAttr` directive. Note that filter templates are only supported in `mod_ldap` version 2.7 and later.

### LDAPUseTLS

Syntax: LDAPUseTLS on|off
Default: off
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_ldap
Compatibility: 1.2.7rc1 and later

The `LDAPUseTLS` directive configures whether `mod_ldap` will use SSL/TLS via STARTTLS to protect the connections made to the configured LDAP servers.

By default, the `mod_ldap` module connects to the LDAP server via non-encrypted connections. Enabling this option causes `mod_ldap` to use an encrypted (TLS/SSL) connection to the LDAP server. If a secure connection to the LDAP server fails, `mod_ldap` will not authenticate users; `mod_ldap` will not fall back to an unsecure connection.

## Installation

Follow the normal steps for using third-party modules in ProFTPD:

      $ ./configure --with-modules=mod_ldap
      $ make
      $ make install

You may need to specify the location of the OpenLDAP header and library files in your `configure` command, e.g.:

     $ ./configure --with-modules=mod_ldap \
        --with-includes=/usr/local/openldap/include \
        --with-libraries=/usr/local/openldap/lib

## Usage

One `mod_ldap` user submitted the following configuration for allowing `mod_ldap` to communicate to a Windows Active Directory server. Note that this configuration has not been tested; if it works for you (or not), please let us know:

      <IfModule mod_ldap.c>
        LDAPServer ldaps://dc.example.org:3268
        LDAPUseTLS on
        LDAPAuthBinds on
        LDAPBindDN "cn=SRV_ACC_SVN_AUTH,ou=special accounts,ou=Sales,dc=example,dc=org" ******************

        LDAPUsers ou=Users,ou=Sales,dc=example,dc=org "(&(sAMAccountName=%u)(objectclass=user)(memberOf=cn=Linux Admins,ou=Groups,ou=Sales,dc=example,dc=com))"
        LDAPSearchScope subtree

        # Assign default IDs
        LDAPDefaultUID 106
        LDAPDefaultGID 65534

        # Create the home directory
        LDAPGenerateHomedir on
        LDAPGenerateHomedirPrefix /home

        # Use different attribute names where necessary
        LDAPAttr uid sAMAccountName
        LDAPAttr gidNumber primaryGroupID
      </IfModule>

Logging
The `mod_ldap` module supports trace logging, via the module-specific log channels:

- ldap
- ldap.library

Thus for trace logging, to aid in debugging, you would use the following in your `proftpd.conf`:

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

This trace logging can generate large files; it is intended for debugging use only, and should be removed from any production configuration.

Frequently Asked Questions

Question: Why is `mod_ldap` using a "base" scope by default, rather than "subtree"? I configured:

      LDAPSearchScope subtree

but it is not working; I see the following in my LDAP server logs:

      slapd[31709]: conn=20239 op=1 SRCH base="ou=people,dc=example,dc=com" scope=0 deref=0 filter="(&(uid=tj)(objectClass=posixAccount))"

Answer: The use of the "base" scope for searches, in spite of any `LDAPSearchScope` directive, happens when a URL, rather than hostname/port, are used in the `LDAPServer` directive. RFC 2255, Section 3 specifies that the default scope is "base".

Thus instead of:

      LDAPServer ldap://ldap.example.com

you will need to use:

      LDAPServer ldap://ldap.example.com/??sub

See the `LDAPSearchScope` documentation for more details.

Question: How do I use `LDAPGenerateHomedir` and `CreateHome` together successfully? Can I use just `LDAPGenerateHomedir`?
Answer: If you want to have home directories for your LDAP users automatically created, you do need to use the `CreateHome` directive. Whether you need to use the `LDAPGenerateHomedir` directive is a different (but related) question.

The `LDAPGenerateHomedir` directive (and its relative `LDAPForceGeneratedHomedir`) should be used when you want to users to have a different home directory than is configured for them in LDAP. They are not used for creating these directories, just generating the paths to use.

Thus to generate a different home directory for your LDAP-defined users, and to have these different home directories created, you might use something like this:

      <IfModule mod_ldap.c>
        ...
        LDAPGenerateHomedir on
        LDAPGenerateHomedirPrefix /data
        LDAPForceGeneratedHomedir on

        # And make sure these home directories are created
        CreateHome on 0770 skel /opt/ProFTPD/etc/skel
        ...
      </IfModule>

Question: In my LDAP server logs, I see ProFTPD make multiple binds for the same client logging in:

      slapd[31709]: conn=20239 op=0 BIND dn="cn=admin,dc=example,dc=com" method=128
      slapd[31709]: conn=20239 op=0 BIND dn="cn=admin,dc=example,dc=com" mech=SIMPLE ssf=0

I was expecting just one bind. Is this a bug, or is it expected behavior?
Answer: Yes, this is the expected behavior. See the `LDAPAuthBinds` directive for details.

© Copyright 2013-2017 TJ Saunders
All Rights Reserved