|
|
| |
Net::FTPServer(3) |
User Contributed Perl Documentation |
Net::FTPServer(3) |
Net::FTPServer - A secure, extensible and configurable Perl FTP server
ftpd.sh [--help] [-d] [-v] [-p port] [-s] [-S] [-V] [-C conf_file]
[-P pidfile] [-o option=value]
"Net::FTPServer" is a secure, extensible and
configurable FTP server written in Perl.
Current features include:
* Authenticated FTP access.
* Anonymous FTP access.
* Complete implementation of current RFCs.
* ASCII or binary type file transfers.
* Active or passive mode file transfers.
* Run standalone or from inetd(8).
* Security features: chroot, resource limits, tainting,
protection against buffer overflows.
* IP-based and/or IP-less virtual hosts.
* Complete access control system.
* Anonymous read-only FTP personality.
* Virtual filesystem allows files to be served
from a database.
* Directory aliases and CDPATH support.
* Extensible command set.
* Generate archives on the fly.
A standard "ftpd.conf" file is supplied with
the distribution. Full documentation for all the possible options which you
may use in this file is contained in this manual page. See the section
CONFIGURATION below.
After doing "make install", the
standard "ftpd.conf" file should have been
installed in "/etc/ftpd.conf". You will
probably need to edit this file to suit your local configuration.
Also after doing "make install",
several start-up scripts will have been installed in
"/usr/sbin/*ftpd.pl". (On Debian in
"/usr/bin" or
"/usr/local/bin"). Each start-up script
starts the server in a different configuration: either as a full FTP server,
or as an anonymous-only read-only FTP server, etc.
The commonly used scripts are:
* /usr/sbin/ftpd.pl
* /usr/sbin/ro-ftpd.pl
The first script is for the full FTP server.
These scripts assume that the
"perl" interpreter can be found on the
current $PATH. In the rare situation when this is
not the case, you may need to edit these scripts.
If you have a high load site, you will want to run
"Net::FTPServer" as a standalone server. To
start "Net::FTPServer" as a standalone
server, do:
/usr/sbin/ftpd.pl -S
You may want to add this to your local start-up files so that the
server starts automatically when you boot the machine.
To stop the server, do:
killall ftpd.pl
(Note: "Azazel" points out that
the above is a Linux-ism. Solaris administrators may get a nasty shock if
they type "killall" as
"root"! Just kill the parent
"ftpd.pl" process by hand instead).
Add the following line to "/etc/inetd.conf":
ftp stream tcp nowait root /usr/sbin/tcpd ftpd.pl
(This assumes that you have the
"tcp-wrappers" package installed to
provide basic access control through
"/etc/hosts.allow" and
"/etc/hosts.deny". This access control is
in addition to any access control which you may configure through
"/etc/ftpd.conf".)
After editing this file you will need to inform
"inetd":
killall -HUP inetd
"xinetd" is a modern alternative to
"inetd" which is supposedly simpler to
configure. In practice, however, it has proven to be quite difficult to
configure services under "xinetd" (mainly
because "xinetd" gives no diagnostic
information when things go wrong). The following configuration has worked for
me:
Create the file
"/etc/xinetd.d/net-ftpserver"
containing:
# default: on
# description: Net::FTPServer, a secure, \
# extensible, configurable FTP server.
#
service ftp
{
socket_type = stream
wait = no
user = root
server = /usr/sbin/ftpd.pl
log_on_success += DURATION USERID
log_on_failure += USERID
disable = no
}
Check any other possible FTP server configurations to ensure they
are all disabled (ie. "disable = yes" in
all other files).
Restart "xinetd" using:
/etc/init.d/xinetd restart
--help Display help and exit
-d, -v Enable debugging
-p PORT Listen on port PORT instead of the default port
-s Run in daemon mode (default: run from inetd)
-S Run in background and in daemon mode
-V Show version information and exit
-C CONF Use CONF as configuration file (default:
/etc/ftpd.conf)
-P PIDFILE Save pid into PIDFILE (daemon mode only)
-o option=value Override config file option with value
--test Test mode (used only in automatic testing scripts)
"Net::FTPServer" can be configured and
extended in a number of different ways.
Firstly, almost all common server configuration can be carried out
by editing the configuration file
"/etc/ftpd.conf".
Secondly, commands can be loaded into the server at run-time to
provide custom extensions to the common FTP command set. These custom
commands are written in Perl.
Thirdly, one of several different supplied personalities
can be chosen. Personalities can be used to make deep changes to the FTP
server: for example, there is a supplied personality which allows the FTP
server to serve files from a relational database. By subclassing
"Net::FTPServer",
"Net::FTPServer::DirHandle" and
"Net::FTPServer::FileHandle" you may also
write your own personalities.
The next sections talk about each of these possibilities in
turn.
A standard "/etc/ftpd.conf" file is supplied
with "Net::FTPServer" in the distribution.
The possible configuration options are listed in full below.
Simple configuration options can also be given on the command line
using the "-o" option. Command line
configuration options override those from the configuration file.
- <Include filename>
- Use the <Include filename> directive to include the contents of
"filename" directly at the current point
within the configuration file.
You cannot use <Include> within a <Host> section,
or at least you can but it won't work the way you expect.
- <IncludeWildcard wildcard>
- Include all files matching "wildcard" at
this point in the file. The files are included in alphabetical order.
You cannot use <IncludeWildcard> within a <Host>
section, or at least you can but it won't work the way you
expect.
- debug
- Run with debugging. Equivalent to the command line
"-d" option.
Default: 0
Example: "debug: 1"
- port
- The TCP port number on which the FTP server listens when running in daemon
mode (see "daemon mode" option below).
Default: The standard ftp/tcp service port from
"/etc/services"
Example: "port: 8021"
- daemon mode
- Run as a daemon. If set, the FTP server will open a listening socket on
its default port number, accept new connections and fork off a new process
to handle each connection. If not set (the default), the FTP server will
handle a single connection on stdin/stdout, which is suitable for use from
inetd.
The equivalent command line options are
"-s" and
"-S".
Default: 0
Example: "daemon mode:
1"
- run in background
- Run in the background. If set, the FTP server will fork into the
background before running.
The equivalent command line option is
"-S".
Default: 0
Example: "run in background:
1"
- error log
- If set, then all warning and error messages are appended to this file. If
not set, warning and error messages get sent to STDERR and to syslog.
Having an error log is highly recommended.
Default: (not set, warnings and errors go to syslog)
Example: "error log:
/var/log/ftpd.errors"
- rotate log files
- If set, and if the log file names contain a '%' directive, then the server
will check if a new log file is needed whenever the system accepts a new
connection. This implements a log rotation feature for long-running
servers.
If not set, then any '%' directive will be evaluated only when
the log files gets created.
Default: (not set, log file name evaluated only once)
Example: "rotate log files:
1"
- maintainer email
- Maintainer's email address.
Default: root@hostname
Example: "maintainer email:
bob@example.com"
- class
- Assign users into classes. One or more
"class" directives can be added to the
configuration file to aggregate individual users into larger groups of
users called classes.
By default all anonymous users are in class
"anonymous" and every other user is in
class "users".
The configuration file can contain zero or more
"class" directives. The format of the
class directive is either:
class: CLASSNAME USERNAME[,USERNAME[,...]]
or:
class: CLASSNAME { perl code ... }
Examples of the first form are:
class: staff rich
class: students ann,mary,pete
User "rich" will be placed
into class "staff", and users
"ann",
"mary" and
"pete" will be placed into class
"students".
Examples of the second form are:
class: family { /jones$/ }
class: friends { $_ ne "jeff" }
Any username ending in
"jones" (eg.
"rjones",
"timjones") will be in class
"family". Any other user except
"jeff" will be placed in class
"friends". Note that the Perl code
must be surrounded by "{...}" and must
return a boolean true or false value. The username is available as
$_. The Perl code is arbitrary: it might, for
example, use an external file or database lookup in order to work out if
a user belongs to a class.
"class" directives are
evaluated in the order in which they appear in the configuration file
until one matches the username.
Default: Anonymous users are assigned to class
"anonymous" and everyone else is
assigned to class "users".
- timeout
- Timeout on control connection. If a command has not been received after
this many seconds, the server drops the connection. You may set this to
zero to disable timeouts completely (although this is not recommended).
Default: 900 (seconds)
Example: "timeout: 600"
- limit memory
- limit nr processes
- limit nr files
- Resource limits. These limits are applied to each child process and are
important in avoiding denial of service (DoS) attacks against the FTP
server.
Resource Default Unit
limit memory 16384 KBytes Amount of memory per child
limit nr processes 10 (none) Number of processes
limit nr files 20 (none) Number of open files
To instruct the server not to limit a particular
resource, set the limit to "-1".
Example:
limit memory: 32768
limit nr processes: 20
limit nr files: 40
limit nr processes: -1
- max clients
- Limit on the number of clients who can simultaneously connect. If this
limit is ever reached, new clients will immediately be closed. It will not
even ask the client to login. This feature works in daemon mode only.
Default: 255
Example: "max clients:
600"
- max clients message
- Message to display when ``max clients'' has been reached.
You may use the following % escape sequences within the
message for internal variables:
%x ``max clients'' setting that has been reached
%E maintainer email address (from ``maintainer email''
setting above)
%G time in GMT
%R remote hostname or IP address if ``resolve addresses''
is not set
%L local hostname
%T local time
%% just an ordinary ``%''
Default: Maximum connections reached
Example: "max clients message: Only %x
simultaneous connections allowed. Please try again
later."
- resolve addresses
- Resolve addresses. If set, attempt to do a reverse lookup on client
addresses for logging purposes. If you set this then some clients may
experience long delays when they try to connect. Not recommended on high
load servers.
Default: 0
Example: "resolve addresses:
1"
- require resolved addresses
- Require resolved addresses. If set, client addresses must validly resolve
otherwise clients will not be able to connect. If you set this then some
clients will not be able to connect, even though it is probably the fault
of their ISP.
Default: 0
Example: "require resolved addresses:
1"
- change process name
- Change process name. If set (the default) then the FTP server will change
its process name to reflect the IP address or hostname of the client. If
not set then the FTP server will not try to change its process name.
Default: 1
Example: "change process name:
0"
- greeting type
- Greeting type. The greeting is printed before the user has logged in.
Possible greeting types are:
full Full greeting, including hostname and version number.
brief Hostname only.
terse Nothing
text Display greeting from ``greeting text'' option.
The SITE VERSION command can also reveal the version number.
You may need to turn this off by setting "allow
site version command: 0" below.
Default: full
Example: "greeting type:
text"
- greeting text
- Greeting text. If the "greeting type" is
set to "text" then this contains the
text to display.
Default: none
Example: "greeting text: Hello. I'll be
your server today."
- welcome type
- Welcome type. The welcome is printed after a user has logged in. Possible
welcome types are:
normal Normal welcome message: ``Welcome <<username>>.''
text Take the welcome message from ``welcome text'' option.
file Take the welcome message from ``welcome file'' file.
Default: normal
Example: "welcome type:
text"
- welcome text
- If "welcome type" is set to
"text", then this contains the text to
be printed after a user has logged in.
You may use the following % escape sequences within the
welcome text to substitute for internal variables:
%E maintainer's email address (from ``maintainer email''
setting above)
%G time in GMT
%R remote hostname or IP address if ``resolve addresses''
is not set
%L local hostname
%m user's home directory (see ``home directory'' below)
%T local time
%U username given when logging in
%u currently a synonym for %U, but in future will be
determined from RFC931 authentication, like wu-ftpd
%% just an ordinary ``%''
Default: none
Example: "welcome text: Welcome to this
FTP server."
- welcome file
- If "welcome type" is set to
"file", then this contains the file to
be printed after a user has logged in.
You may use any of the % escape sequences defined in
"welcome text" above.
Default: none
Example: "welcome file:
/etc/motd"
- home directory
- Home directory. This is the home directory where we put the user once they
have logged in. This only applies to non-anonymous logins. Anonymous
logins are always placed in "/", which is at the root of their
chrooted environment.
You may use an absolute path here, or else one of the
following special forms:
%m Use home directory from password file or from NSS.
%U Username.
%% A single % character.
For example, to force a user to start in
"~/anon-ftp" when they log in, set
this to "%m/anon-ftp".
Note that setting the home directory does not perform a
chroot. Use the "root directory"
setting below to jail users into a particular directory.
Home directories are relative to the current root
directory.
In the anonymous read-only (ro-ftpd) personality, set home
directory to "/" or else you will get
a warning whenever a user logs in.
Default: %m
Examples:
home directory: %m/anon-ftp
home directory: /
- root directory
- Root directory. Immediately after logging in, perform a chroot into the
named directory. This only applies to non-anonymous logins, and
furthermore it only applies if you have a non-database VFS installed.
Database VFSes typically cannot perform chroot (or, to be more accurate,
they have a different concept of chroot - typically assigning each user
their own completely separate namespace).
You may use %m and
%U as above.
For example, to jail a user under
"~/anon-ftp" after login, do:
home directory: /
root directory: %m/anon-ftp
Notice that the home directory is relative to the
current root directory.
Default: (none)
Example: "root directory:
%m/anon-ftp"
- time zone
- Time zone to be used for MDTM and LIST stat information.
Default: GMT
Examples:
time zone: Etc/GMT+3
time zone: Europe/London
time zone: US/Mountain
- local address
- Local addresses. If you wish the FTP server (in daemon mode) to only bind
to a particular local interface, then give its address here.
Default: none
Example: "local address:
127.0.0.1"
- allow anonymous
- Allow anonymous access. If set, then allow anonymous access through the
"ftp" and
"anonymous" accounts.
Default: 0
Example: "allow anonymous:
1"
- anonymous password check
- anonymous password enforce
- Validate email addresses. Normally when logging in anonymously, you are
asked to enter your email address as a password. These options can be used
to check and enforce email addresses in this field (to some extent, at
least -- you obviously can't force someone to enter a true email address).
The "anonymous password
check" option may be set to
"rfc822", "no
browser", "trivial" or
"none". If set to
"rfc822" then the user must enter a
valid RFC 822 email address as password. If set to
"no browser" then a valid RFC 822
email address must be entered, and various common browser email
addresses like "mozilla@" and
"IEverUser@"
are refused. If set to "trivial" then
we just check that the address contains an @ char. If set to
"none", then we do no checking. The
default is "none".
If the "anonymous password
enforce" option is set and the password fails the check
above, then the user will not be allowed to log in. The default is 0
(unset).
These options only have effect when
"allow anonymous" is set.
Example:
anonymous password check: rfc822
anonymous password enforce: 1
- allow proxy ftp
- Allow proxy FTP. If this is set, then the FTP server can be told to
actively connect to addresses and ports on any machine in the world. This
is not such a great idea, but required if you follow the RFC very closely.
If not set (the default), the FTP server will only connect back to the
client machine.
Default: 0
Example: "allow proxy ftp:
1"
- allow connect low port
- Allow the FTP server to connect back to ports < 1024. This is rarely
useful and could pose a serious security hole in some circumstances.
Default: 0
Example: "allow connect low port:
1"
- passive port range
- What range of local ports will the FTP server listen on in passive mode?
Choose a range here like
"1024-5999,49152-65535". The special
value 0 means that the FTP server will use a
kernel-assigned ephemeral port.
Default: 49152-65535
Example: "passive port range:
0"
- ftp data port
- Which source port to use for active (non-passive) mode when connecting to
the client for PORT mode transfers. The special value
0 means that the FTP server will use a
kernel-assigned ephemeral port. To strictly follow RFC, this should be set
to "ftp-data(20)". This may be required
for certain brain-damaged firewall configurations. However, for security
reasons, the default setting is intentionally set to
0 to utilize a kernel-assigned ephemeral port. Use
this directive at your own risk!
SECURITY PRECAUTIONS:
1) Unfortunately, to use a port < 1024 requires super-user
privileges. Thus, low ports will not work unless the FTP server is
invoked as super-user. This also implies that all processes handling the
client connections must also remain super-user throughout the
entire session. It is highly discouraged to use a low port.
http://cr.yp.to/ftp/security.html
(See "Connection laundering" section)
2) There sometimes exists a danger of needing to connect to
the same remote host:port. Using the same IP/port on both sides will
cause connect() to fail if the old socket is still being broken
down. This condition will not occur if using an ephemeral port.
http://groups.google.com/groups?selm=fa.epucqgv.1l2kl0e@ifi.uio.no
(See "unable to create socket" comment)
3) Many hackers use source port 20 to blindly circumvent
certain naive firewalls. Using an ephemeral port (the default) may help
discourage such dangerous naivety.
man nmap
(See the -g option)
Default: 0
Example: "ftp data port:
ftp-data"
- max login attempts
- Maximum number of login attempts before we drop the connection and issue a
warning in the logs. Wu-ftpd defaults this to 5.
Default: 3
Example: "max login attempts:
5"
- pam authentication
- Use PAM for authentication. Required on systems such as Red Hat Linux and
Solaris which use PAM for authentication rather than the normal
"/etc/passwd" mechanisms. You will need
to have the "Authen::PAM" Perl module
installed for this to work.
Default: 0
Example: "pam authentication:
1"
- pam application name
- If PAM authentication is enabled, then this is the PAM application name. I
have used "ftp" as the default which is
the same name that wu-ftpd chooses. FreeBSD users will want to use
"ftpd" here.
Default: ftp
Example: "pam application name:
ftpd"
- password file
- Only in the "Full" personality, this
allows you to specify a password file which is used for authentication. If
you enable this option, then normal PAM or
"/etc/passwd" is bypassed and this
password file is used instead.
Each line in the password file has the following format:
username:crypted_password:unix_user[:root_directory]
Comments and blank lines are ignored.
For example, a line with:
guest:ab01FAX.bQRSU:rich:/home/rich/guest-uploads
would allow someone to log in as
"guest" with password
123456. After logging in, the FTP server will
assume the identity of the real Unix user
"rich", and will chroot itself into
the "/home/rich/guest-uploads"
directory.
(Note that because ordinary
PAM/"passwd" is bypassed, it would no
longer be possible for a user to log in directly with the username
"rich").
Crypted passwords can be generated using the following
command:
perl -e 'print crypt ("123456", "ab"), "\n"'
Replace 123456 with the actual
password, and replace "ab" with two
random letters from the set
"[a-zA-Z0-9./]". (The two random
letters are the so-called salt and are used to make dictionary
attacks against the password file more difficult - see
crypt(3)).
The user's home directory comes from the real Unix password
file (or nsswitch-configured source) for the real Unix user. You cannot
use password files to override this, and so if you are using the
optional "root_directory" parameter,
it would make sense to add "home directory:
/" into your configuration file.
Anonymous logins are not affected by the
"password file" option. Use the
"allow anonymous" flag to control
whether anonymous logins are permitted in the
"Full" back-end.
Password files are not the height of security, but they are
included because they can sometimes be useful. In particular if the
password file can be read by untrusted users then it is likely that
those same users can run the crack program and eventually find
out your passwords. Some small additional security is offered by having
the password file readable only by root (mode 0600). In future we may
offer MD5 or salted SHA-1 hashed passwords to make this harder.
A curious artifact of the implementation allows you to list
the same user with multiple different passwords. Any of the passwords is
then valid for logins (and you could even have the user map to different
real Unix users in different chrooted directories!)
Default: (none)
Example: "password file:
/etc/ftpd.passwd"
- pidfile
- Location of the file to store the process ID (PID). Applies only to the
deamonized process, not the child processes.
Default: (no pidfile created)
Example: "pidfile:
/var/run/ftpd.pid"
- client logging
- Location to store all client commands sent to the server. The format is
the date, the pid, and the command. Following the pid is a "-"
if not authenticated the username if the connection is authenticated.
Example of before and after authentication:
[Wed Feb 21 18:41:32 2001][23818:-]USER rob
[Wed Feb 21 18:41:33 2001][23818:-]PASS 123456
[Wed Feb 21 18:41:33 2001][23818:*]SYST
Default: (no logging)
Examples:
client logging: /var/log/ftpd.log
client logging: /tmp/ftpd_log.$hostname
- xfer logging
- Location of transfer log. The format was taken from wu-ftpd and ProFTPD
xferlog. (See also "man xferlog")
Default: (no logging)
Examples:
xfer logging: /var/log/xferlog
xfer logging: /tmp/xferlog.$hostname
- hide passwords in client log
- If set to 1, then password ("PASS")
commands will not be logged in the client log. This option has no effect
unless client logging is enabled.
Default: 0 (PASS lines will be shown)
Example: "hide passwords in client log:
1"
- enable syslog
- Enable syslogging. If set, then Net::FTPServer will send much information
to syslog. On many systems, this information will be available in
/var/log/messages or /var/adm/messages. If clear, syslogging is disabled.
Default: 1
Example: "enable syslog:
0"
- ident timeout
- Timeout for ident authentication lookups. A timeout (in seconds) must be
specified in order to enable ident lookups. There is no way to specify an
infinite timeout. Use 0 to disable this feature.
Default: 0
Example: "ident timeout:
10"
- access control rule
- user access control rule
- retrieve rule
- store rule
- delete rule
- list rule
- mkdir rule
- rename rule
- chdir rule
- Access control rules.
Access control rules are all specified as short snippets of
Perl script. This allows the maximum configurability -- you can express
just about any rules you want -- but at the price of learning a little
Perl.
You can use the following variables from the Perl:
$hostname Resolved hostname of the client [1]
$ip IP address of the client
$user User name [2]
$class Class of user [2]
$user_is_anonymous True if the user is an anonymous user [2]
$pathname Full pathname of the file being affected [2]
$filename Filename of the file being affected [2,3]
$dirname Directory name containing file being affected [2]
$type 'A' for ASCII, 'B' for binary, 'L8' for local 8-bit
$form Always 'N'
$mode Always 'S'
$stru Always 'F'
Notes:
[1] May be undefined, particularly if
"resolve addresses" is not set.
[2] Not available in "access control
rule" since the user has not logged in at this point.
[3] Not available for "list directory
rule".
Access control rule. The FTP server will not accept any
connections from a site unless this rule succeeds. Note that only
$hostname and $ip are
available to this rule, and unless "resolve
addresses" and "require resolved
addresses" are both set $hostname
may be undefined.
Default: 1
Examples:
(a) Deny connections from *.badguys.com:
access control rule: defined ($hostname) && \
$hostname !~ /\.badguys\.com$/
(b) Only allow connections from local network 10.0.0.0/24:
access control rule: $ip =~ /^10\./
User access control rule. After the user logs in successfully,
this rule is then called to determine if the user may be permitted
access.
Default: 1
Examples:
(a) Only allow ``rich'' to log in from 10.x.x.x network:
user access control rule: $user ne "rich" || \
$ip =~ /^10\./
(b) Only allow anonymous users to log in if they come from
hosts with resolving hostnames (``resolve addresses'' must
also be set):
user access control rule: !$user_is_anonymous || \
defined ($hostname)
(c) Do not allow user ``jeff'' to log in at all:
user access control rule: $user ne "jeff"
Retrieve rule. This rule controls who may retrieve (download)
files.
Default: 1
Examples:
(a) Do not allow anyone to retrieve ``/etc/*'' or any file anywhere
called ``.htaccess'':
retrieve rule: $dirname !~ m(^/etc/) && $filename ne ".htaccess"
(b) Only allow anonymous users to retrieve files from under the
``/pub'' directory.
retrieve rule: !$user_is_anonymous || $dirname =~ m(^/pub/)
Store rule. This rule controls who may store (upload)
files.
In the anonymous read-only (ro-ftpd) personality, it is not
possible to upload files anyway, so setting this rule has no effect.
Default: 1
Examples:
(a) Only allow users to upload files to the ``/incoming''
directory.
store rule: $dirname =~ m(^/incoming/)
(b) Anonymous users can only upload files to ``/incoming''
directory.
store rule: !$user_is_anonymous || $dirname =~ m(^/incoming/)
(c) Disable file upload.
store rule: 0
Delete rule. This rule controls who may delete files or rmdir
directories.
In the anonymous read-only (ro-ftpd) personality, it is not
possible to delete files anyway, so setting this rule has no effect.
Default: 1
Example: "delete rule:
0"
List rule. This rule controls who may list out the contents of
a directory.
Default: 1
Example: "list rule: $dirname =~
m(^/pub/)"
Mkdir rule. This rule controls who may create a
subdirectory.
In the anonymous read-only (ro-ftpd) personality, it is not
possible to create directories anyway, so setting this rule has no
effect.
Default: 1
Example: "mkdir rule: 0"
Rename rule. This rule controls which files or directories can
be renamed.
Default: 1
Example: "rename rule: $pathname !~
m(/.htaccess$)"
Chdir rule. This rule controls which directories are
acceptable to a CWD or CDUP.
Example: "chdir rule: $pathname !~
m/private/"
- chdir message file
- Change directory message file. If set, then the first time (per session)
that a user goes into a directory which contains a file matching this
name, that file will be displayed.
The file may contain any of the following % escape
sequences:
%C current working directory
%E maintainer's email address (from ``maintainer email''
setting above)
%G time in GMT
%R remote hostname or IP address if ``resolve addresses''
is not set
%L local hostname
%m user's home directory (see ``home directory'' below)
%T local time
%U username given when logging in
%u currently a synonym for %U, but in future will be
determined from RFC931 authentication, like wu-ftpd
%% just an ordinary ``%''
Default: (none)
Example: "chdir message file:
.message"
- allow rename to overwrite
- Allow the rename (RNFR/RNTO) command to overwrite files. If unset, then we
try to test whether the rename command would overwrite a file and disallow
it. However there are some race conditions with this test.
Default: 1
Example: "allow rename to overwrite:
0"
- allow store to overwrite
- Allow the store commands (STOR/STOU/APPE) to overwrite files. If unset,
then we try to test whether the store command would overwrite a file and
disallow it. However there are some race conditions with this test.
Default: 1
Example: "allow store to overwrite:
0"
- alias
- Define an alias "name" for directory
"dir". For example, the command
"alias: mirror /pub/mirror" would allow
the user to access the "/pub/mirror"
directory directly just by typing "cd
mirror".
Aliases only apply to the cd (CWD) command. The
"cd foo" command checks for
directories in the following order:
foo in the current directory
an alias called foo
foo in each directory in the cdpath (see ``cdpath'' command below)
You may list an many aliases as you want.
Alias names cannot contain slashes (/).
Although alias dirs may start without a slash (/), this is
unwise and it's better that they always start with a slash (/) char.
General format: "alias:
name
dir"
- cdpath
- Define a search path which is used when changing directories. For example,
the command "cdpath: /pub/mirror
/pub/sites" would allow the user to access the
"/pub/mirror/ftp.cpan.org" directory
directly by just typing "cd
ftp.cpan.org".
The "cd foo" command checks
for directories in the following order:
foo in the current directory
an alias called foo (see ``alias'' command above)
foo in each directory in the cdpath
General format: "cdpath:
dir1
[dir2
[dir3 ...]]"
- allow site version command
- SITE VERSION command. If set, then the SITE VERSION command reveals the
current Net::FTPServer version string. If unset, then the command is
disabled.
Default: 1
Example: "allow site version command:
0"
- allow site exec command
- SITE EXEC command. If set, then the SITE EXEC command allows arbitrary
commands to be executed on the server as the current user. If unset, then
this command is disabled. The default is disabled for obvious security
reasons.
If you do allow SITE EXEC, you may need to increase the per
process memory, processes and files limits above.
Default: 0
Example: "allow site exec command:
1"
- enable archive mode
- Archive mode. If set (the default), then archive mode is enabled, allowing
users to request, say, "file.gz" and get
a version of "file" which is
gzip-compressed on the fly. If zero, then this feature is disabled. See
the section ARCHIVE MODE elsewhere in this manual for details.
Since archive mode is implemented using external commands, you
need to ensure that programs such as
"gzip",
"compress",
"bzip2",
"uuencode", etc. are available on the
$PATH (even in the chrooted environment), and
you also need to substantially increase the normal per-process memory,
processes and files limits.
Default: 1
Example: "enable archive mode:
0"
- archive zip temporaries
- Temporary directory for generating ZIP files in archive mode. In archive
mode, when generating ZIP files, the FTP server is capable of either
creating a temporary file on local disk containing the ZIP contents, or
can generate the file completely in memory. The former method saves
memory. The latter method (only practical on small ZIP files) allows the
server to work more securely and in certain read-only chrooted
environments.
(Unfortunately the ZIP file format itself prevents ZIP files
from being easily created on the fly).
If not specified in the configuration file, this option
defaults to using "/tmp". If there are
local users on the FTP server box, then this can lead to various
"tmp" races, so for maximum security
you will probably want to change this.
If specified, and set to a string, then the string is the name
of a directory which is used for storing temporary zip files. This
directory must be writable, and must exist inside the chrooted
environment (if chroot is being used).
If specified, but set to "0" or an empty string,
then the server will always generate the ZIP file in memory.
In any case, if the directory is found at runtime to be
unwritable, then the server falls back to creating ZIP files in
memory.
Default: "/tmp"
Example: "archive zip temporaries:
"
Example: "archive zip temporaries:
/var/ziptmp"
- site command
- Custom SITE commands. Use this command to define custom SITE commands.
Please read the section LOADING CUSTOMIZED SITE COMMANDS in this manual
page for more detailed information.
The "site command" command
has the form:
"site command:
cmdname
file"
cmdname is the name of the command (eg. for SITE README
you would set cmdname ==
"readme"). file is a file
containing the code of the site command in the form of an anonymous Perl
subroutine. The file should have the form:
sub {
my $self = shift; # The FTPServer object.
my $cmd = shift; # Contains the command itself.
my $rest = shift; # Contains any parameters passed by the user.
: :
: :
$self->reply (RESPONSE_CODE, RESPONSE_TEXT);
}
You may define as many site commands as you want. You may also
override site commands from the current personality here.
Example:
site command: quota /usr/local/lib/ftp/quota.pl
and the file
"/usr/local/lib/ftp/quota.pl"
contains:
sub {
my $self = shift; # The FTPServer object.
my $cmd = shift; # Contains "QUOTA".
my $rest = shift; # Contains parameters passed by user.
# ... Some code to compute the user's quota ...
$self->reply (200, "Your quota is $quota MB.");
}
The client types "SITE
QUOTA" and the server responds with:
"200 Your quota is 12.5 MB.".
- <Host hostname> ... </Host>
- <Host hostname> ... </Host> encloses commands which are
applicable only to a particular host.
"hostname" may be either a
fully-qualified domain name (for IP-less virtual hosts) or an IP address
(for IP-based virtual hosts). You should read the section VIRTUAL HOSTS in
this manual page for more information on the different types of virtual
hosts and how to set it up in more detail.
Note also that unless you have set
"enable virtual hosts: 1", all
<Host> sections will be ignored.
- enable virtual hosts
- Unless this option is uncommented, virtual hosting is disabled and the
<Host> sections in the configuration file have no effect.
Default: 0
Example: "enable virtual hosts:
1"
- virtual host multiplex
- IP-less virtual hosts. If you want to enable IP-less virtual hosts, then
you must set up your DNS so that all hosts map to a single IP address, and
place that IP address here. This is roughly equivalent to the Apache
"NameVirtualHost" option.
IP-less virtual hosting is an experimental feature which
requires changes to clients.
Default: (none)
Example: "virtual host multiplex:
1.2.3.4"
Example <Host> section. Allow the dangerous SITE EXEC
command on local connections. (Note that this is still dangerous).
<Host localhost.localdomain>
ip: 127.0.0.1
allow site exec command: 1
</Host>
Example <Host> section. This shows you how to do
IP-based virtual hosts. I assume that you have set up your DNS so that
"ftp.bob.example.com" maps to IP
1.2.3.4 and
"ftp.jane.example.com" maps to IP
1.2.3.5, and you have set up suitable IP
aliasing in the kernel.
You do not need the "ip:"
command if you have configured reverse DNS correctly AND you trust your
local DNS servers.
<Host ftp.bob.example.com>
ip: 1.2.3.4
root directory: /home/bob
home directory: /
user access control rule: $user eq "bob"
maintainer email: bob@bob.example.com
</Host>
<Host ftp.jane.example.com>
ip: 1.2.3.5
root directory: /home/jane
home directory: /
allow anonymous: 1
user access control rule: $user_is_anonymous
maintainer email: jane@jane.example.com
</Host>
These rules set up two virtual hosts called
"ftp.bob.example.com" and
"ftp.jane.example.com". The former is
located under bob's home directory and only he is allowed to log in. The
latter is located under jane's home directory and only allows anonymous
access.
Example <Host> section. This shows you how to do IP-less
virtual hosts. Note that IP-less virtual hosts are a highly experimental
feature, and require the client to support the HOST command.
You need to set up your DNS so that both
"ftp.bob.example.com" and
"ftp.jane.example.com" point to your
own IP address.
virtual host multiplex: 1.2.3.4
<Host ftp.bob.example.com>
root directory: /home/bob
home directory: /
user access control rule: $user eq "bob"
</Host>
<Host ftp.jane.example.com>
root directory: /home/jane
home directory: /
allow anonymous: 1
user access control rule: $user_is_anonymous
</Host>
- log socket type
- Socket type for contacting syslog. This is the argument to the
"Sys::Syslog::setlogsock" function.
Default: unix
Example: "log socket type:
inet"
- listen queue
- Length of the listen queue when running in daemon mode.
Default: 10
Example: "listen queue:
20"
- tcp window
- Set TCP window. See RFC 2415 Simulation Studies of Increased Initial
TCP Window Size. This setting only affects the data socket. It's not
likely that you will need to or should change this setting from the
system-specific default.
Default: (system-specific TCP window size)
Example: "tcp window:
4380"
- tcp keepalive
- Set TCP keepalive.
Default: (system-specific keepalive setting)
Example: "tcp keepalive:
1"
- command filter
- Command filter. If set, then all commands are checked against this regular
expression before being executed. If a command doesn't match the filter,
then the command connection is immediately dropped. This is equivalent to
the "AllowFilter" command in ProFTPD.
Remember to include "^...$" around the
filter.
Default: (no filter)
Example: "command filter: ^[A-Za-z0-9
/]+$"
- restrict command
- Advanced command filtering. The "restrict
command" directive takes the form:
restrict command: "COMMAND" perl code ...
If the user tries to execute
"COMMAND", then the
"perl code" is evaluated first. If it
evaluates to true, then the command is allowed to proceed. Otherwise the
server reports an error back to the user and does not execute the
command.
Note that the "COMMAND" is
the FTP protocol command, which is not necessarily the same as the
command which users will type in on their FTP clients. Please read RFC
959 to see some of the more common FTP protocol commands.
The Perl code has the same variables available to it as for
access control rules (eg. $user,
$class, $ip, etc.). The
code must not alter the global $_
variable (which contains the complete command).
Default: all commands are allowed by default
Examples:
Only allow users in the class
"nukers" to delete files and
directories:
restrict command: "DELE" $class eq "nukers"
restrict command: "RMD" $class eq "nukers"
Only allow staff to use the "SITE
WHO" command:
restrict command: "SITE WHO" $class eq "staff"
Only allow "rich" to run the
"SITE EXEC" command:
allow site exec command: 1
restrict command: "SITE EXEC" $user eq "rich"
- command wait
- Go slow. If set, then the server will sleep for this many seconds before
beginning to process each command. This command would be a lot more useful
if you could apply it only to particular classes of connection.
Default: (no wait)
Example: "command wait:
5"
- no authentication commands
- The list of commands which a client may issue before they have
authenticated themselves is very limited. Obviously
"USER" and
"PASS" are allowed (otherwise a user
would never be able to log in!), also
"QUIT",
"LANG",
"HOST" and
"FEAT".
"HELP" is also permitted (although
dubious). Any other commands not on this list will result in a 530 Not
logged in. error.
This list ought to contain at least
"USER",
"PASS" and
"QUIT" otherwise the server won't be
very functional.
Some commands cannot be added here -- eg. adding
"CWD" or
"RETR" to this list is likely to make
the FTP server crash, or else enable users to read files only available
to root. Hence use this with great care.
Default: USER PASS QUIT LANG HOST FEAT HELP
Example: "no authentication commands:
USER PASS QUIT"
- <Perl> ... </Perl>
- Use the <Perl> directive to write Perl code directly into your
configuration file. Here is a simple example:
<Perl>
use Sys::Hostname;
$config{'maintainer email'} = "root\@" . hostname ();
$config{port} = 8000 + 21;
$config{debug} = $ENV{FTP_DEBUG} ? 1 : 0;
</Perl>
As shown in the example, to set a configuration option called
"foo", you simply assign to the
variable $config{foo}.
All normal Perl functionality is available to you, including
use of "require" if you need to run an
external Perl script.
The <Perl> and </Perl> directives must each appear
on a single line on their own.
To assign multiple configuration options with the same name,
use an array ref:
<Perl>
my @aliases = ( "foo /pub/foo",
"bar /pub/bar",
"baz /pub/baz" );
$config{alias} = \@aliases;
</Perl>
You cannot use a <Perl> section within a <Host>
section. Instead, you must simulate it by assigning to the
%host_config variable like this:
<Perl>
$host_config{'localhost.localdomain'}{ip} = "127.0.0.1";
$host_config{'localhost.localdomain'}{'allow site exec command'}= 1;
</Perl>
The above is equivalent to the following ordinary <Host>
section:
<Host localhost.localdomain>
ip: 127.0.0.1
allow site exec command: 1
</Host>
You may also assign to the $self
variable in order to set variables directly in the
"Net::FTPServer" object itself. This
is pretty hairy, and hence not recommended, but you dig your own hole if
you want. Here is a contrived example:
<Perl>
$self->{version_string} = "my FTP server/1.0";
</Perl>
A cleaner, but more complex way to do this would be to use a
personality.
The <Perl> directive is potentially quite powerful. Here
is a good idea that Rob Brown had:
<Perl>
my %H;
dbmopen (%H, "/etc/ftpd.db", 0644);
%config = %H;
dbmclose (%H);
</Perl>
Notice how this allows you to crunch a possibly very large
configuration file into a hash, for very rapid loading at run time.
Another useful way to use <Perl> is to set environment
variables (particularly $PATH).
<Perl>
$ENV{PATH} = "/usr/local/bin:$ENV{PATH}"
</Perl>
Here's yet another wonderful way to use <Perl>. Look in
"/usr/local/lib/ftp/" for a list of
site commands and load each one:
<Perl>
my @files = glob "/usr/local/lib/ftp/*.pl";
my @site_commands;
foreach (@files)
{
push @site_commands, "$1 $_" if /([a-z]+)\.pl/;
}
$config{'site command'} = \@site_commands;
</Perl>
To force a particular version of Net::FTPServer to be used,
include the following code in your configuration file:
<Perl>
die "requires Net::FTPServer version >= 1.025"
unless $Net::FTPServer::VERSION !~ /\..*\./ &&
$Net::FTPServer::VERSION >= 1.025;
</Perl>
It is very simple to write custom SITE commands. These commands are available to
users when they type "SITE XYZ" in a command line FTP client or when
they define a custom SITE command in their graphical FTP client.
SITE commands are unregulated by RFCs. You may define any commands
and give them any names and any function you wish. However, over time
various standard SITE commands have been recognized and implemented in many
FTP servers. "Net::FTPServer" also
implements these. They are:
SITE VERSION Display the server software version.
SITE EXEC Execute a shell command on the server (in
C<Net::FTPServer> this is disabled by default!)
SITE ALIAS Display chdir aliases.
SITE CDPATH Display chdir paths.
SITE CHECKMETHOD Implement checksums.
SITE CHECKSUM
SITE IDLE Get or set the idle timeout.
SITE SYNC Synchronize hard disks.
The following commands are found in
"wu-ftpd", but not currently implemented
by "Net::FTPServer": SITE CHMOD, SITE
GPASS, SITE GROUP, SITE GROUPS, SITE INDEX, SITE MINFO, SITE NEWER, SITE
UMASK.
So when you are choosing a name for a SITE command, it is probably
best not to choose one of the above names, unless you are specifically
implementing or overriding that command.
Custom SITE commands have to be written in Perl. However, there is
very little you need to understand in order to write these commands -- you
will only need a basic knowledge of Perl scripting.
As our first example, we will implement a
"SITE README" command. This command just
prints out some standard information.
Firstly create a file called
"/usr/local/lib/site_readme.pl" (you may
choose a different path if you want). The file should contain:
sub {
my $self = shift;
my $cmd = shift;
my $rest = shift;
$self->reply (200,
"This is the README file for mysite.example.com.",
"Mirrors are contained in /pub/mirrors directory.",
" : : : : :",
"End of the README file.");
}
Edit "/etc/ftpd.conf" and add
the following command:
site command: readme /usr/local/lib/site_readme.pl
and restart the FTP server (check your system log
[/var/log/messages] for any syntax errors or other problems). Here is an
example of a user running the SITE README command:
ftp> quote help site
214-The following commands are recognized:
214- ALIAS CHECKMETHOD EXEC README
214- CDPATH CHECKSUM IDLE VERSION
214 You can also use HELP to list general commands.
ftp> site readme
200-This is the README file for mysite.example.com.
200-Mirrors are contained in /pub/mirrors directory.
200- : : : : :
200 End of the README file.
Our second example demonstrates how to use parameters (the
$rest argument). This is the
"SITE ECHO" command.
sub {
my $self = shift;
my $cmd = shift;
my $rest = shift;
# Split the parameters up.
my @params = split /\s+/, $rest;
# Quote each parameter.
my $reply = join ", ", map { "'$_'" } @params;
$self->reply (200, "You said: $reply");
}
Here is the "SITE ECHO" command
in use:
ftp> quote help site
214-The following commands are recognized:
214- ALIAS CHECKMETHOD ECHO IDLE
214- CDPATH CHECKSUM EXEC VERSION
214 You can also use HELP to list general commands.
ftp> site echo hello how are you?
200 You said: 'hello', 'how', 'are', 'you?'
Our third example is more complex and shows how to interact with
the virtual filesystem (VFS). The "SITE
SHOW" command will be used to list text files directly (the user
normally has to download the file and view it locally). Hence
"SITE SHOW readme.txt" should print the
contents of the "readme.txt" file in the
local directory (if it exists).
All file accesses must be done through the VFS, not by
directly accessing the disk. If you follow this convention then your
commands will be secure and will work correctly with different back-end
personalities (in particular when ``files'' are really blobs in a relational
database).
sub {
my $self = shift;
my $cmd = shift;
my $rest = shift;
# Get the file handle.
my ($dirh, $fileh, $filename) = $self->_get ($rest);
# File doesn't exist or not accessible. Return an error.
unless ($fileh)
{
$self->reply (550, "File or directory not found.");
return;
}
# Check it's a simple file.
my ($mode) = $fileh->status;
unless ($mode eq "f")
{
$self->reply (550,
"SITE SHOW command is only supported on plain files.");
return;
}
# Try to open the file.
my $file = $fileh->open ("r");
unless ($file)
{
$self->reply (550, "File or directory not found.");
return;
}
# Copy data into memory.
my @lines = ();
while (defined ($_ = $file->getline))
{
# Remove any native line endings.
s/[\n\r]+$//;
push @lines, $_;
}
# Close the file handle.
unless ($file->close)
{
$self->reply (550, "Close failed: ".$self->system_error_hook());
return;
}
# Send the file back to the user.
$self->reply (200, "File $filename:", @lines, "End of file.");
}
This code is not quite complete. A better implementation would
also check the "retrieve rule" (so that people couldn't use
"SITE SHOW" in order to get around access
control limitations which the server administrator has put in place). It
would also check the file more closely to make sure it was a text file and
would refuse to list very large files.
Here is an example (abbreviated) of a user using the
"SITE SHOW" command:
ftp> site show README
200-File README:
200-README
200-======
200-
200-Biblio@Tech Net::FTPServer - A full-featured, secure, extensible
[...]
200-Copyright (C) 2000-2003 Richard Jones <rich@annexia.org> and other contributors.
200 End of file.
Currently "Net::FTPServer" is supplied with
three standard personalities. These are:
Full The complete read/write anonymous/authenticated FTP
server which serves files from a standard Unix filesystem.
RO A small read-only anonymous-only FTP server similar
in functionality to Dan Bernstein's publicfile
program.
DBeg1 An example FTP server which serves files to a PostgreSQL
database. This supports files and hierarchical
directories, multiple users (but not file permissions)
and file upload.
The standard Full personality will not be explained
here.
The RO personality is the Full personality with all code
related to writing files, creating directories, deleting, etc. removed. The
RO personality also only permits anonymous logins and does not contain any
code to do ordinary authentication. It is therefore safe to use the RO
personality where you are only interested in serving files to anonymous
users and do not want to worry about crackers discovering a way to trick the
FTP server into writing over a file.
The DBeg1 personality is a complete read/write FTP server
which stores files as BLOBs (Binary Large OBjects) in a PostgreSQL
relational database. The personality supports file download and upload and
contains code to authenticate users against a
"users" table in the database (database
``users'' are thus completely unrelated to real Unix users). The
DBeg1 is intended only as an example. It does not support advanced
features such as file permissions and quotas. As part of the
schoolmaster.net project Bibliotech Ltd. have developed an even more
advanced database personality which supports users, groups, access control
lists, quotas, recursive moves and copies and many other features. However
this database personality is not available as source.
To use the DBeg1 personality you must first run a PostgreSQL
server (version 6.4 or above) and ensure that you have access to it from
your local user account. Use the "initdb",
"createdb" and
"createuser" commands to create the
appropriate user account and database (please consult the PostgreSQL
administrators manual for further information about this -- I do not answer
questions about basic PostgreSQL knowledge).
Here is my correctly set up PostgreSQL server, accessed from my
local user account ``rich'':
cruiser:~$ psql
Welcome to the POSTGRESQL interactive sql monitor:
Please read the file COPYRIGHT for copyright terms of POSTGRESQL
type \? for help on slash commands
type \q to quit
type \g or terminate with semicolon to execute query
You are currently connected to the database: rich
rich=> \d
Couldn't find any tables, sequences or indices!
You will also need the following Perl modules installed: DBI,
DBD::Pg.
Now you will need to create a database called ``ftp'' and populate
it with data. This is how to do this:
createdb ftp
psql ftp < doc/eg1.sql
Check that no ERRORs are reported by PostgreSQL.
You should now be able to start the FTP server by running the
following command (not as root):
./dbeg1-ftpd -S -p 2000 -C ftpd.conf
If the FTP server doesn't start correctly, you should check the
system log file [/var/log/messages].
Connect to the FTP server as follows:
ftp localhost 2000
Log in as either rich/123456 or dan/123456 and then try to move
around, upload and download files, create and delete directories, etc.
By subclassing "Net::FTPServer",
"Net::FTPServer::DirHandle" and/or
"Net::FTPServer::FileHandle" you can create
custom personalities for the FTP server.
Typically by overriding the hooks in the
"Net::FTPServer" class you can change the
basic behaviour of the FTP server - turning it into an anonymous read-only
server, for example.
By overriding the hooks in
"Net::FTPServer::DirHandle" and
"Net::FTPServer::FileHandle" you can
create virtual filesystems: serving files into and out of a database, for
example.
The current manual page contains information about the hooks in
"Net::FTPServer" which may be
overridden.
See Net::FTPServer::DirHandle(3) for
information about the methods in
"Net::FTPServer::DirHandle" which may be
overridden.
See Net::FTPServer::FileHandle(3) for
information about the methods in
"Net::FTPServer::FileHandle" which may be
overridden.
The most reasonable way to create your own personality is to
extend one of the existing personalities. Choose the one which most closely
matches the personality that you want to create. For example, suppose that
you want to create another database personality. A good place to start would
be by copying
"lib/Net/FTPServer/DBeg1/*.pm" to a new
directory "lib/Net/FTPServer/MyDB/" (for
example). Now edit these files and substitute "MyDB" for
"DBeg1". Then examine each subroutine in these files and modify
them, consulting the appropriate manual page if you need to.
"Net:FTPServer" is capable of hosting multiple
FTP sites on a single machine. Because of the nature of the FTP protocol,
virtual hosting is almost always done by allocating a single separate IP
address per FTP site. However,
"Net::FTPServer" also supports an
experimental IP-less virtual hosting system, although this requires
modifications to the client.
Normal (IP-based) virtual hosting is carried out as follows:
* For each FTP site, allocate a separate IP address.
* Configure IP aliasing on your normal interface so that
the single physical interface responds to multiple
virtual IP addresses.
* Add entries (A records) in DNS mapping each site's
name to a separate IP address.
* Add reverse entries (PTR records) in DNS mapping each
IP address back to the site hostname. It is important
that both forward and reverse DNS is set up correctly,
else virtual hosting may not work.
* In /etc/ftpd.conf you will need to add a virtual host
section for each site like this:
<Host sitename>
ip: 1.2.3.4
... any specific configuration options for this site ...
</Host>
You don't in fact need the "ip:" part assuming that
your forward and reverse DNS are set up correctly.
* If you want to specify a lot of external sites, or
generate the configuration file automatically from a
database or a script, you may find the <Include filename>
syntax useful.
There are examples in
"/etc/ftpd.conf". Here is how IP-based
virtual hosting works:
* The server starts by listening on all interfaces.
* A connection arrives at one of the IP addresses and a
process is forked off.
* The child process finds out which interface the
client connected to and reverses the name.
* If:
the IP address matches one of the "ip:" declarations
in any of the "Host" sections,
or:
there is a reversal for the name, and the name
matches one of the "Host" sections in the configuration
file,
then:
configuration options are read from that
section of the file and override any global configuration
options specified elsewhere in the file.
* Otherwise, the global configuration options only
are used.
IP-less virtual hosting is an experimental feature. It requires
the client to send a "HOST" command very
early on in the command stream -- before
"USER" and
"PASS". The
"HOST" command explicitly gives the
hostname that the FTP client is attempting to connect to, and so allows many
FTP sites to be multiplexed onto a single IP address. At the present time, I
am not aware of any FTP clients which implement the
"HOST" command, although they will
undoubtedly become more common in future.
This is how to set up IP-less virtual hosting:
* Add entries (A or CNAME records) in DNS mapping the
name of each site to a single IP address.
* In /etc/ftpd.conf you will need to list the same single
IP address to which all your sites map:
virtual host multiplex: 1.2.3.4
* In /etc/ftpd.conf you will need to add a virtual host
section for each site like this:
<Host sitename>
... any specific configuration options for this site ...
</Host>
Here is how IP-less virtual hosting works:
* The server starts by listening on one interface.
* A connection arrives at the IP address and a
process is forked off.
* The IP address matches "virtual host multiplex"
and so no IP-based virtual host processing is done.
* One of the first commands that the client sends is
"HOST" followed by the hostname of the site.
* If there is a matching "Host" section in the
configuration file, then configuration options are
read from that section of the file and override any
global configuration options specified elsewhere in
the file.
* If there is no matching "Host" section then the
global configuration options alone are used.
The client is not permitted to issue the
"HOST" command more than once, and is not
permitted to issue it after login.
Only certain configuration options are available inside the <Host>
sections of the configuration file. Generally speaking, the only configuration
options you can put here are ones which take effect after the site name has
been determined -- hence "allow anonymous" is OK (since it's an
option which is parsed after determining the site name and during log in), but
"port" is not (since it is parsed long before any clients ever
connect).
Make sure your default global configuration is secure. If you are
using IP-less virtual hosting, this is particularly important, since if the
client never sends a "HOST" command, the
client gets the global configuration. Even with IP-based virtual hosting it
may be possible for clients to sometimes get the global configuration, for
example if your local name server fails.
IP-based virtual hosting always takes precedence above IP-less
virtual hosting.
With IP-less virtual hosting, access control cannot be performed
on a per-site basis. This is because the client has to issue commands (ie.
the "HOST" command at least) before the
site name is known to the server. However you may still have a global
"access control rule".
Beginning with version 1.100, "Net::FTPServer"
is able to generate certain types of compressed and archived files on the fly.
In practice what this means is that if a user requests, say,
"file.gz" and this file does not actually
exist (but "file" does exist), then
the server will dynamically generate a gzip-compressed version of
"file" for the user. This also works on
directories, so that a user might request
"dir.tar.gz" which does not exist (but
directory "dir" does exist), and the
server tars up and compresses the entire contents of
"dir" and presents that back to the user.
Archive mode is enabled by default. However, it will not work
unless you substantially increase the per-process memory, processes and
files limits. The reason for this is that archive mode works by forking
external programs such as "gzip" to
perform the compression. For the same reason you may also need to ensure
that at least "gzip",
"compress",
"bzip2" and
"uuencode" programs are available on the
current $PATH, particularly if you are using a
chrooted environment.
To disable archive mode put "enable archive
mode: 0" into the configuration file.
The following file extensions are supported:
.gz GZip compressed. Requires gzip program on PATH.
.Z Unix compressed. Requires compress program on PATH.
.bz2 BZip2 compressed. Requires bzip2 program on PATH.
.uue UU-encoded. Requires uuencode program on PATH.
.tar Tar archive. Requires Perl Archive::Tar module.
.zip DOS ZIP archive. Requires Perl Archive::Zip module.
.list Return a list of all the files in this directory.
File extensions may be combined. Hence
".tar.gz",
".tar.bz2" and even
".tar.gz.uue" will all work as you
expect.
Archive mode is, of course, extensible. It is particularly simple
to add another compression / filter format. In your personality (or in a
<Perl> section in the configuration file) you need to add another key
to the "archive_filters" hash.
$ftps->{archive_filters}{".foo"} = &_foo_filter;
The value of this key should be a function as defined below:
\%filter = _foo_filter ($ftps, $sock);
The filter should return a hash reference (undef if it fails). The
hash should contain the following keys:
sock Newly opened socket.
pid PID of filter program.
The "_foo_filter" function takes
the existing socket and filters it, providing a new socket which the FTP
server will write to (for the data connection back to the client). If your
filter is a Unix program, then the simplest thing is just to define
"_foo_filter" as:
sub _foo_filter
{
return $_[0]->archive_filter_external ($_[1], "foo" [, args ...]);
}
The "archive_filter_external"
function takes care of the tricky bits for you.
Adding new generators (akin to the existing tar and ZIP) is
more tricky. I suggest you look closely at the code and consult the author
for more information.
- Net::FTPServer->run ([\@ARGV]);
- This is the main entry point into the FTP server. It starts the FTP server
running. This function never normally returns.
If no arguments are given, then command line arguments are
taken from the global @ARGV array.
- $regex = $ftps->wildcard_to_regex ($wildcard)
- This is a general library function shared between many of the back-end
database personalities. It converts a general wildcard (eg. *.c) into a
regular expression (eg. ^.*\.c$ ).
Thanks to: Terrence Monroe Brannon
<terrence.brannon@oracle.com>.
- $regex = $ftps->wildcard_to_sql_like ($wildcard)
- This is a general library function shared between many of the back-end
database personalities. It converts a general wildcard (eg. *.c) into the
strange wildcardish format used by SQL LIKE operator (eg. %.c).
- $ftps->reply ($code, $line, [$line, ...])
- This function sends a standard single line or multi-line FTP server reply
to the client. The $code should be one of the
standard reply codes listed in RFC 959. The one or more
$line arguments are the (free text) of the reply.
Do not include carriage returns at the end of each
$line. This function adds the correct line ending
format as specified in the RFC.
- $ftps->log ($level, $message, ...);
- This function is identical to the normal
"syslog" function to be found in
"Sys::Syslog". However, it only uses
syslog if the "enable syslog"
configuration option is set to true.
Use this function instead of calling
"syslog" directly.
- $ftps->config ($name);
- Read configuration option $name from the
configuration file.
- $ftps->ip_host_config ($ip_addr);
- Look for a <Host> section which contains "ip:
$ip_addr". If one is found, return the site
name of the Host section. Otherwise return undef.
- $filter = $ftps->archive_filter_external ($sock, $cmd [, $args]);
- Apply $cmd as a filter to socket
$sock. Returns a hash reference which contains the
following keys:
sock Newly opened socket.
pid PID of filter program.
If it fails, returns
"undef".
See section ARCHIVE MODE elsewhere in this manual for more
information.
- $ftps->visit ($dirh, \%functions);
- The "visit" function recursively
"visits" every file and directory contained in
$dirh (which must be a directory handle).
"\%functions" is a reference
to a hash of file types to functions. For example:
'f' => \&visit_file,
'd' => \&visit_directory,
'l' => \&visit_symlink,
&c.
When a file of the known type is encountered, the appropriate
function is called with $_ set to the file
handle. (All functions are optional: if
"visit" encounters a file with a type
not listed in the %functions hash, then that
file is just ignored).
The return value from functions is ignored, except for
the return value from the directory ('d') function. The directory
function should return 1 to indicate that
"visit" should recurse into that
directory. If the directory function returns 0, then
"visit" will skip that directory.
"visit" will call the
directory function once for $dirh.
- $sock = $self->open_data_connection;
- Open a data connection. Returns the socket (an instance of
"IO::Socket") or undef if it fails for
some reason.
- $self->pre_configuration_hook ();
- Hook: Called before command line arguments and configuration file are
read.
Status: optional.
Notes: You may append your own information to
"$self->{version_string}" from this
hook.
- $self->options_hook (\@args);
- Hook: Called before command line arguments are parsed.
Status: optional.
Notes: You can use this hook to supply your own command line
arguments. If you parse any arguments, you should remove them from the
@args array.
- $self->post_configuration_hook ();
- Hook: Called after all command line arguments and configuration file have
been read and parsed.
Status: optional.
- $self->post_bind_hook ();
- Hook: Called only in daemon mode after the control port is bound but
before starting the accept infinite loop block.
Status: optional.
- $self->pre_accept_hook ();
- Hook: Called in daemon mode only just before
accept(2) is called in the parent FTP server
process.
Status: optional.
- $self->post_accept_hook ();
- Hook: Called both in daemon mode and in inetd mode just after the
connection has been accepted. This is called in the child process.
Status: optional.
- $rv = $self->access_control_hook;
- Hook: Called after accept(2)-ing the connection to
perform access control. Detailed request information is contained in the
$self object. If the function returns -1 then the
socket is immediately closed and no FTP processing happens on it. If the
function returns 0, then normal access control is performed on the socket
before FTP processing starts. If the function returns 1, then normal
access control is not performed on the socket and FTP processing
begins immediately.
Status: optional.
- $rv = $self->process_limits_hook;
- Hook: Called after accept(2)-ing the connection to
perform per-process limits (eg. by using the setrlimit(2) system
call). Access control has already been performed and detailed request
information is contained in the $self object.
If the function returns -1 then the socket is immediately
closed and no FTP processing happens on it. If the function returns 0,
then normal per-process limits are applied before any FTP processing
starts. If the function returns 1, then normal per-process limits are
not performed and FTP processing begins immediately.
Status: optional.
- $rv = $self->authentication_hook ($user, $pass, $user_is_anon)
- Hook: Called to perform authentication. If the authentication succeeds,
this should return 0 (or any positive integer >= 0). If the
authentication fails, this should return -1.
Status: required.
- $self->user_login_hook ($user, $user_is_anon)
- Hook: Called just after user $user has
successfully logged in. A good place to change uid and chroot if
necessary.
Status: optional.
- $dirh = $self->root_directory_hook;
- Hook: Return an instance of a subclass of Net::FTPServer::DirHandle
corresponding to the root directory.
Status: required.
- $self->pre_command_hook;
- Hook: This hook is called just before the server begins to wait for the
client to issue the next command over the control connection.
Status: optional.
- $rv = $self->command_filter_hook ($cmdline);
- Hook: This hook is called immediately after the client issues command
$cmdline, but before any checking or
processing is performed on the command. If this function returns -1, then
the server immediately goes back to waiting for the next command. If this
function returns 0, then normal command filtering is carried out and the
command is processed. If this function returns 1 then normal command
filtering is not performed and the command processing begins
immediately.
Important Note: This hook must be careful not to
overwrite the global $_ variable.
Do not use this function to add your own commands. Instead use
the "$self->{command_table}" and
"$self->{site_command_table}"
hashes.
Status: optional.
- $error = $self->transfer_hook ($mode, $file, $sock, \$buffer);
-
$mode - Open mode on the File object (Either reading or writing)
$file - File object as returned from DirHandle::open
$sock - Data IO::Socket object used for transfering
\$buffer - Reference to current buffer about to be written
The \$buffer is passed by reference to minimize the stack
overhead for efficiency purposes only. It is not meant to be
modified by the transfer_hook subroutine. (It can cause corruption if
the length of $buffer is modified.)
Hook: This hook is called after reading
$buffer and before writing
$buffer to its destination. If arg1 is
"r", $buffer was read from the File
object and written to the Data socket. If arg1 is "w",
$buffer will be written to the File object
because it was read from the Data Socket. The return value is the error
for not being able to perform the write. Return undef to avoid aborting
the transfer process.
Status: optional.
- $self->post_command_hook ($cmd, $rest)
- Hook: This hook is called after all command processing has been carried
out on this command. $cmd is the command, and
$rest is the remainder of the command line.
Status: optional.
- $self->system_error_hook
- Hook: This hook is used instead of $! when what looks like a system error
occurs during a virtual filesystem handle method. It can be used by the
virtual filesystem to provide explanatory text for a virtual filesystem
failure which did not actually set the real $!.
Status: optional.
- $self->quit_hook
- Hook: This hook is called after the user has
"QUIT" or if the FTP client cleanly
drops the connection. Please note, however, that this hook is not
called whenever the FTP server exits, particularly in cases such as:
* The FTP server, the Perl interpreter or the personality
crashes unexpectedly.
* The user fails to log in.
* The FTP server detects a fatal error, sends a "421" error code,
and abruptly exits.
* Idle timeouts.
* Access control violations.
* Manual server shutdowns.
Unfortunately it is not in general easily possible to catch
these cases and cleanly call a hook. If your personality needs to do
cleanup in all cases, then it is probably better to use an
"END" block inside your Server object
(see perlmod(3)). Even using an
"END" block cannot catch cases where
the Perl interpreter crashes.
Status: optional.
The SIZE, REST and RETR commands probably do not work correctly in ASCII mode.
REST does not work before STOR/STOU/APPE (is it supposed to?)
User upload/download limits.
Limit number of clients by host or IP address.
The following commands are recognized by
"wu-ftpd", but are not yet implemented by
"Net::FTPServer":
SITE CHMOD There is a problem supporting this with our VFS.
SITE GPASS Group functions are not really relevant for us.
SITE GROUP -"- ditto -"-
SITE GROUPS -"- ditto -"-
SITE INDEX This is a synonym for SITE EXEC.
SITE MINFO This command is no longer supported by wu-ftpd.
SITE NEWER This command is no longer supported by wu-ftpd.
SITE UMASK This command is difficult to support with VFS.
Symbolic links are not handled elegantly (or indeed at all)
yet.
Equivalent of ProFTPD's ``DisplayReadme'' function.
The ability to hide dot files (probably best to build this into
the VFS layer). This should apply across all commands. See ProFTPD's
``IgnoreHidden'' function.
Access to LDAP authentication database (can currently be done
using a PAM module). In general, we should support pluggable
authentication.
Log formatting similar to ProFTPD command LogFormat.
More timeouts to avoid various denial of service attacks. For
example, the server should always timeout when waiting too long for an
active data connection.
Support for IPv6 (see RFC 2428), EPRT, EPSV commands.
See also "XXX" comments in the code for other problems,
missing features and bugs.
Richard Jones (rich@annexia.org), Rob Brown (bbb@cpan.org), Keith Turner (keitht
at silvaco.com), Azazel (azazel at azazel.net), and many others.
Ryo Okamoto "<ryo at aquahill dot net>"
https://github.com/ryochin/p5-net-ftpserver
Copyright (C) 2000 Biblio@Tech Ltd., Unit 2-3, 50 Carnwath Road, London, SW6
3EG, UK.
Copyright (C) 2000-2003 Richard Jones (rich@annexia.org) and other
contributors.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Net::FTPServer::Handle(3),
Net::FTPServer::FileHandle(3),
Net::FTPServer::DirHandle(3),
Net::FTP(3), perl(1), RFC 765,
RFC 959, RFC 1579, RFC 2389, RFC 2428, RFC 2577, RFC 2640, Extensions to FTP
Internet Draft draft-ietf-ftpext-mlst-NN.txt. Net::FTPServer::XferLog
Test::FTP::Server
Visit the GSP FreeBSD Man Page Interface. Output converted with ManDoc. |