## ProFTPD module `mod_log`

This module is contained in the `mod_log.c` file for ProFTPD 1.3.x, and is compiled by default.

## Directives

- AllowLogSymlinks
- ExtendedLog
- LogFormat
- LogOptions
- ServerLog
- SystemLog

### AllowLogSymlinks

Syntax: AllowLogSymlinks on|off
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_log
Compatibility: 1.2.2rc2 and later

By default, the server will the path of any configured `SystemLog`, any configured `TransferLog`s, and any configured `ExtendedLog`s to see if they are symbolic links. If the paths are symbolic links, `proftpd` will refuse to log to that link unless explicitly configured to do so via this `AllowLogSymlinks` directive.

Security Note: This behaviour should not be allowed unless for a very good reason. By allowing the server to open symbolic links with its root privileges, you are allowing a potential symlink attack where the server could be tricked into overwriting arbitrary system files. You have been warned.

### ExtendedLog

Syntax: ExtendedLog path [cmd-classes [format-name]]
Default: None
Context: server config, `<VirtualHost>`, `<Global>`, `<Anonymous>`
Module: mod_log
Compatibility: 1.1.6p11 and later

The `ExtendedLog` directive allows customizable logfiles to be generated, either globally or per `<VirtualHost>`. The path argument should contain an absolute pathname to a logfile which will be appended to when `proftpd` starts; the pathname should not be to a file in a nonexistent directory, to a world-writable directory, or be a symbolic link (unless `AllowLogSymlinks` is set to on). Multiple logfiles, potentially with different command classes and formats) can be created. Optionally, the cmd-classes parameter can be used to control which types of commands are logged. If no command classes are specified, `proftpd` logs all commands by default. Note that passwords are hidden. If used, the cmd-classes parameter is a comma-delimited (with no whitespace) list of which commands to log.

In `proftpd-1.2.8rc1` and later, the path argument can be of the form "syslog:level". The "syslog:" prefix configures `mod_log` to write the `ExtendedLog` data to syslog rather than to a file. The level configures the syslog level at which to log the data. For example:

      ExtendedLog syslog:info ALL default

This table shows the supported command classes:

Command Class | FTP Commands
`ALL` | All commands except the `EXIT` pseudo-command (default)
`NONE` | No commands
`AUTH` | Authentication commands: `ACCT`, `PASS`, `REIN`, `USER`
`INFO` | Informational commands: `FEAT`, `HELP`, `MDTM`, `QUIT`, `PWD`, `STAT`, `SIZE`, `SYST`, `XPWD`
`DIRS` | Directory commands: `CDUP`, `CWD`, `LIST`, `MKD`, `MLSD`, `MLST`, `NLST`, `RMD`, `XCWD`, `XCUP`, `XMKD`, `XRMD`
`READ` | File reading: `RETR`
`WRITE` | File/directory writing or creation: `APPE`, `MFF`, `MFMT`, `MKD`, `RMD`, `RNFR`, `RNTO`, `STOR`, `STOU`, `XMKD`, `XRMD`
`MISC` | Miscellaneous commands: `ABOR`, `ALLO`, `EPRT`, `EPSV`, `MODE`, `NOOP`, `OPTS`, `PASV`, `PORT`, `REST`, `RNFR`, `RNTO`, `SITE`, `SMNT`, `STRU`, `TYPE`
`SEC` | RFC2228-related security FTP commands: `AUTH`, `CCC`, `PBSZ`, `PROT`. Note: this class also includes SSH key exchange commands.
`EXIT` | Logs the configured `LogFormat` at session exit. NOTE: `EXIT` is not part of the `ALL` command class, in order to preserve backward-compatible `ALL` behavior.

If a format-name parameter is used, `ExtendedLog` will use the named `LogFormat`. Otherwise, the default format of "%h %l %u %t \"%r\" %s %b" is used.

For example, to log all read and write operations to `/var/log/ftp.log` using the default format, use:

      ExtendedLog /var/log/ftp.log READ,WRITE

and to log all read and write operations to `/var/log/ftp.log` using your own `LogFormat` named "custom", use:

      LogFormat custom ...
      ExtendedLog /var/log/ftp.log READ,WRITE custom

See also: `AllowLogSymlinks`, `LogFormat`, `TransferLog`

### LogFormat

Syntax: LogFormat format-name format-string
Default: LogFormat default "%h %l %u %t \"%r\" %s %b"
Context: server config, `<Global>`
Module: mod_log
Compatibility: 1.1.6p11 and later

The `LogFormat` directive can be used to create a custom logging format for use with the `ExtendedLog` directive. Once created, the format can be referenced by the specified format-name. The format-string parameter can consist of any combination of letters, numbers and symbols. The special character '%' is used to start a meta sequence/variable (see below). To insert a literal '%' character, use "%%".

The default `LogFormat` is:

      "%h %l %u %t \"%r\" %s %b"

which produces log entries in the Common Log Format.

The following meta sequences/variables are available and are replaced as indicated when logging.

Variable | Value
`%a` | Remote client IP address
`%A` | Anonymous login password, or "UNKNOWN" for regular logins
`%{basename}` | Last component of path, i.e. just the file or directory name.
`%b` | Number of bytes sent for this command
`%c` | Client connection class, or "-" if undefined
`%d` | Directory name (not full path) for: `CDUP`, `CWD`, `LIST`, `MLSD`, `MKD`, `NLST`, `RMD`, `XCWD`, `XCUP`, `XMKD`, `XRMD`
`%D` | Directory path (full path) for: `CDUP`, `CWD`, `LIST`, `MLSD`, `MKD`, `NLST`, `RMD`, `XCWD`, `XCUP`, `XMKD`, `XRMD`
`%E` | End-of-session reason
`%{epoch}` | Unix epoch; seconds since January 1, 1970
`%{NAME}e` | Contents of environment variable NAME
`%f` | Absolute path of the filename stored or retrieved (not chrooted)
`%F` | Filename stored or retrieved, as the client sees it
`%{file-modified}` | Indicates whether a file is modified (i.e. already exists): "true" or "false"
`%{file-size}` | Indicates the file size after data transfer, or "-" if not applicable
`%{gid}` | GID of authenticated user
`%g` | Primary group of authenticated user
`%h` | Remote client DNS name
`%H` | Local IP address of vhost/server hosting/handling the session
`%I` | Total number of "raw" bytes read in from network
`%{iso8601}` | shorthand form of `%{%Y-%m-%d %H:%M:%S}t,%{millisecs}`, e.g. "2013-01-30 20:14:05,670"
`%J` | Command arguments received from client, e.g. "file.txt"
`%l` | Remote username (from `identd`), or "UNKNOWN" if IdentLookup failed
`%L` | Local IP address contacted by client
`%m` | Command (method) name received from client, e.g. `RETR`
`%{microsecs}` | 6 digit value of the microseconds of the current time
`%{millisecs}` | 3 digit value of the milliseconds of the current time
`%O` | Total number of "raw" bytes written out to network
`%p` | Local port
`%P` | Local server process ID (pid)
`%{protocol}` | Current protocol: "ftp", "ftps", "ssh2", "sftp", "scp"
`%r` | Full command received from client
`%R` | Response time, in milliseconds
`%{remote-port}` | Remote client port
`%s` | Numeric FTP response code (status); see RFC 959 Section 4.2.1
`%S` | Response message sent to client (available since 1.3.1rc1)
`%t` | Current local time
`%{format}t` | Current local time using `strftime(3)` format
`%T` | Time taken to transfer file, in seconds
`%{transfer-failure}` | Reason for data transfer failure (if applicable), or "-"
`%{transfer-millisecs}` | Time taken to transfer file, in milliseconds
`%{transfer-port}` | Remote port used for data transfer
`%{transfer-speed}`%nbsp; | Data transfer speed, in KB/s
`%{transfer-status}` | Status of data transfer: "success", "failed", "cancelled", "timeout", or "-"
`%{transfer-type}` | Data transfer type: "binary" or "ASCII" (if applicable), or "-"
`%u` | Authenticated local username
`%U` | `USER` name originally sent by client
`%{uid}` | UID of authenticated user
`%v` | Local server `ServerName`
`%V` | Local server DNS name
`%{version}` | ProFTPD version
`%w` | Absolute path for the `RNFR` path ("whence" a rename comes)

See also: `ExtendedLog`, `TransferLog`

### LogOptions

Syntax: LogOptions opt1 ... optN
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_core
Compatibility: 1.3.7rc4 and later

The `LogOptions` directive can be used to change the format of the `SystemLog` messages, e.g. adding/remove certain fields of data. These options also apply to all module logging; ProFTPD logging is centralized, and the `LogOptions` are applied to any/all logging.

The options supported by the `LogOptions` directive are:

- Hostname
- RoleBasedProcessLabels
- Timestamp
- VirtualHost

All of these options are enabled by default, except for the `RoleBasedProcessLabels` option.

To enable an option, preface the option name with a '+' (plus) character; to disable the option, use a '-' (minus) character prefix. For example:

      # Log messages without timestamps or hostname
      LogOptions -Hostname -Timestamp

The `RoleBasedProcessLabels` option changes the label just for the PID, from e.g.:

      proftpd[1234]

to one of the following, depending on whether the process is the master daemon process, or a forked session process:

      daemon[2345]
      session[34567]

This is useful, for example, when relying on `systemd` logging:

      LogOptions -Timestamp -Hostname +RoleBasedProcessLabels

### ServerLog

Syntax: ServerLog path|"none"
Default: None
Context: server config, `<VirtualHost>`, `<Global>`
Module: mod_log
Compatibility: 1.2.8rc1 and later

The `ServerLog` directive is used to configure a `<VirtualHost>`-specific logfile at the given path, rather than a single `SystemLog` for the entire configuration.

A path value of "none" will disable file logging for that vhost; this can be used to override a global `ServerLog` setting.

### SystemLog

Syntax: SystemLog path|"none"
Default: None
Context: server config, `<Global>`
Module: mod_log
Compatibility: 1.1.6p11 and later

The `SystemLog` directive disables ProFTPD's use of the `syslog` mechanism and instead redirects all logging output to the specified path. The path should contain an absolute path, and should not be to a file in a nonexistent directory, in a world-writable directory, or be a symbolic link (unless `AllowLogSymlinks` is set to on).

Use of this directive overrides any facility set by the `SyslogFacility` directive.

A path value of "none" will disable logging for the entire daemon.

If you find that your ProFTPD installation appears to be ignoring your `SystemLog` configuration entirely, and your ProFTPD service is managed/run by `systemd`, then you may be encountering this FAQ.

## Installation

The `mod_log` module is compiled by default.

## Usage

Frequently Asked Questions

Question: Why are successful logins no longer being logged, after upgrading to ProFTPD 1.3.6, even though I am using the `SystemLog` directive?
Answer: The default log level was changed from `DEBUG` to `NOTICE` in ProFTPD 1.3.6; see Bug#3983. And the "Login successful" log message is logged at the `INFO` level, which means that it will not be logged by default.

Why not? The `INFO` log level is for "normal operating conditions" (see the log levels howto), and successful logins are considered normal, and thus are not noteworthy or needed for logging. Failed logins, however, are logged at the `NOTICE` log level.

For having successful logins logged once more, use the following in your `proftpd.conf`:

      SyslogLevel INFO

Question: I configured `SystemLog` in my ProFTPD configuration, but ProFTPD still logs only to syslog. What is missing?
Answer: The most common cause for this behavior is the use of `systemd` for running ProFTPD. In particular, the `systemd` unit file for ProFTPD in some installations unexpectedly uses the `--nodaemon` command-line option, e.g.:

    # /usr/lib/systemd/system/proftpd.service
    ...
    [Service]
    Type = simple
    Environment = PROFTPD_OPTIONS=
    EnvironmentFile = -/etc/sysconfig/proftpd
    ExecStartPre = /usr/sbin/proftpd --configtest
    ExecStart = /usr/sbin/proftpd --nodaemon $PROFTPD_OPTIONS
    ExecReload = /bin/kill -HUP $MAINPID
    PIDFile = /run/proftpd/proftpd.pid

    ...

When ProFTPD is started with the `-n/--nodaemon` command-line option, it will only log to stdout, and not to any configured log files. This configuration is useful, for example, when running ProFTPD in a Docker container.

A slightly different `systemd` unit file for ProFTPD will work just as well, and will honor the `SystemLog` configuration as expected:

    ...
    [Service]
    Type = forking
    Environment = PROFTPD_OPTIONS=
    EnvironmentFile = -/etc/sysconfig/proftpd
    ExecStartPre = /usr/sbin/proftpd --configtest $PROFTPD_OPTIONS
    ExecStart = /usr/sbin/proftpd $PROFTPD_OPTIONS
    ExecReload = /bin/kill -HUP $MAINPID
    PIDFile = /run/proftpd/proftpd.pid

    ...

Question: I have configured ProFTPD to use DNS names in my `proftpd.conf` using:

      UseReverseDNS on

But in my `ExtendedLog`, I still see IP addresses rather than the DNS names I expect to see. How can that happen?
Answer: The `LogFormat` `%h` is what is used to log DNS names. The logged value might be an IP address if ProFTPD cannot properly verify that the client IP address resolves to a DNS name.

"Properly verifying" an IP address, in this case, means resolving the DNS name for an IP address and then resolving that DNS name back to its IP addresses:

      $ host 10.1.2.3
      3.2.1.10.in-addr.arpa domain name pointer host.domain.example.com.
      $ host host.domain.example.com
      host.domain.example.com has address 10.4.5.6

In this example, the IP address 10.1.2.3 does not resolve back to itself via DNS, but rather to a different IP address.

If the DNS name does not resolve back to the original IP address, then that DNS name is not used, as that DNS name is considered "unreliable"; only reliable information is logged (and used elsewhere). Thus ProFTPD resorts to logging just the client IP address for the `%h` variable, rather than the DNS name, in these situations.

Question: How can I get the reason a client was disconnected, for whatever reason, logged to my `ExtendedLog`?
Answer: You can use the `%E` `LogFormat` variable for this, in conjunction with the `EXIT` log class.

For example, assume you have configured the following:

      MaxConnectionsPerUser 2

and you would like your `ExtendedLog` to record when this limit is reached. To do this, you would use something like the following:

      LogFormat eos "%a: user=%U disconnect_reason=\"%E\""
      ExtendedLog /var/log/proftpd/ext.log EXIT eos

Of course, you can include other logging classes than just `EXIT`; the above is just an example.

With the above, when the `MaxConnectionsPerUser` is reached, your log would have a line like:

      127.0.0.1: user=tj disconnect_reason="Denied by MaxConnectionsPerUser"

© Copyright 2002-2023 The ProFTPD Project
All Rights Reserved