Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages


home | help
Net::FTPServer(3)     User Contributed Perl Documentation    Net::FTPServer(3)

       Net::FTPServer -	A secure, extensible and configurable Perl FTP server

SYNOPSIS [--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

       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/*". (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/
	* /usr/sbin/

       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,

	 /usr/sbin/ -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:


       (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 "" process by hand instead).

       Add the following line to "/etc/inetd.conf":

	 ftp stream tcp	nowait root /usr/sbin/tcpd

       (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/
	       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:
	 -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

       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

	   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.

	   Run with debugging. Equivalent to the command line "-d" option.

	   Default: 0

	   Example: "debug: 1"

	   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:"

	   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 { 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 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".


	    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"

	   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


	    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

	   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

	   Default: (none)

	   Example: "root directory: %m/anon-ftp"

       time zone
	   Time	zone to	be used	for MDTM and LIST stat information.

	   Default: GMT


	    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

	   Default: none

	   Example: "local address:"

       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.


	    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

	   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!


	   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.
	    (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.
	    (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:


	   Comments and	blank lines are	ignored.

	   For example,	a line with:


	   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

	   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"

	   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/"

       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)


	    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)


	    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

	   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'


	   [1] May be undefined, particularly if "resolve addresses" is	not

	   [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

	   Default: 1


	    (a)	Deny connections from *

		access control rule: defined ($hostname) && \
				     $hostname !~ /\.badguys\.com$/

	    (b)	Only allow connections from local network

		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

	   Default: 1


	    (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)

	   Default: 1


	    (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

	   Default: 1


	    (a)	Only allow users to upload files to the	``/incoming''

		store rule: $dirname =~	m(^/incoming/)

	    (b)	Anonymous users	can only upload	files to ``/incoming''

		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

	   In the anonymous read-only (ro-ftpd)	personality, it	is not
	   possible to delete files anyway, so setting this rule has no

	   Default: 1

	   Example: "delete rule: 0"

	   List	rule. This rule	controls who may list out the contents of a

	   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

	   Default: 1

	   Example: "mkdir rule: 0"

	   Rename rule.	This rule controls which files or directories can be

	   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"

	   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"

	   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/" directory
	   directly by just typing "cd".

	   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.


	    site command: quota	/usr/local/lib/ftp/

	   and the file	"/usr/local/lib/ftp/" 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:"

	   Example <Host> section. Allow the dangerous SITE EXEC command on
	   local connections. (Note that this is still dangerous).

	    <Host localhost.localdomain>
	      allow site exec command: 1

	   Example <Host> section. This	shows you how to do IP-based virtual
	   hosts. I assume that	you have set up	your DNS so that
	   "" maps to IP and	""
	   maps	to IP, and you have set	up suitable IP aliasing	in the

	   You do not need the "ip:" command if	you have configured reverse
	   DNS correctly AND you trust your local DNS servers.

	      root directory: /home/bob
	      home directory: /
	      user access control rule:	$user eq "bob"
	      maintainer email:

	      root directory: /home/jane
	      home directory: /
	      allow anonymous: 1
	      user access control rule:	$user_is_anonymous
	      maintainer email:

	   These rules set up two virtual hosts	called ""
	   and "". 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 "" and
	   "" point	to your	own IP address.

	    virtual host multiplex:

	      root directory: /home/bob
	      home directory: /
	      user access control rule:	$user eq "bob"

	      root directory: /home/jane
	      home directory: /
	      allow anonymous: 1
	      user access control rule:	$user_is_anonymous

       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


	   Only	allow users in the class "nukers" to delete files and

	    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

	   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.


	   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:

	    use	Sys::Hostname;
	    $config{'maintainer	email'}	= "root\@" . hostname ();
	    $config{port} = 8000 + 21;
	    $config{debug} = $ENV{FTP_DEBUG} ? 1 : 0;

	   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:

	    my @aliases	= ( "foo /pub/foo",
			    "bar /pub/bar",
			    "baz /pub/baz" );
	    $config{alias} = \@aliases;

	   You cannot use a <Perl> section within a <Host> section. Instead,
	   you must simulate it	by assigning to	the %host_config variable like

	    $host_config{'localhost.localdomain'}{ip} =	"";
	    $host_config{'localhost.localdomain'}{'allow site exec command'}= 1;

	   The above is	equivalent to the following ordinary <Host> section:

	    <Host localhost.localdomain>
	      allow site exec command: 1

	   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:

	    $self->{version_string} = "my FTP server/1.0";

	   A cleaner, but more complex way to do this would be to use a

	   The <Perl> directive	is potentially quite powerful.	Here is	a good
	   idea	that Rob Brown had:

	    my %H;
	    dbmopen (%H, "/etc/ftpd.db", 0644);
	    %config = %H;
	    dbmclose (%H);

	   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).

	    $ENV{PATH} = "/usr/local/bin:$ENV{PATH}"

	   Here's yet another wonderful	way to use <Perl>.  Look in
	   "/usr/local/lib/ftp/" for a list of site commands and load each


	    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;


	   To force a particular version of Net::FTPServer to be used, include
	   the following code in your configuration file:

	     die "requires Net::FTPServer version >= 1.025"
	       unless $Net::FTPServer::VERSION !~ /\..*\./ &&
		      $Net::FTPServer::VERSION >= 1.025;

       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

       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 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,

       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/" (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",
			 "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/

       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 You can also use HELP to list general commands.
	 ftp> site readme
	 200-This is the README	file for
	 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 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

       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.");

	   # 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.");

	   # Try to open the file.
	   my $file = $fileh->open ("r");

	   unless ($file)
	       $self->reply (550, "File	or directory not found.");

	   # Copy data into memory.
	   my @lines = ();

	   while (defined ($_ =	$file->getline))
	       # Remove	any native line	endings.

	       push @lines, $_;

	   # Close the file handle.
	   unless ($file->close)
	       $self->reply (550, "Close failed: ".$self->system_error_hook());

	   # 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"

	 ftp> site show	README
	 200-File README:
	 200-Biblio@Tech Net::FTPServer	- A full-featured, secure, extensible
	 200-Copyright (C) 2000-2003 Richard Jones <> 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

	 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	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

       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

       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>

	      ... any specific configuration options for this site ...


	  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,
	    there is a reversal	for the	name, and the name
	    matches one	of the "Host" sections in the configuration
	    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

       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:

	* 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 ...


       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

       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 <>.

       $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

       $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

       $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,

	   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

	   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

	   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.

	   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

	   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.

	   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.

	   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.

       IO::Dir,	IO::stringy

       Richard Jones (, Rob Brown (, Keith
       Turner (keitht at, Azazel (azazel at, and many

       Ryo Okamoto "<ryo at aquahill dot net>"


       Copyright (C) 2000 Biblio@Tech Ltd., Unit 2-3, 50 Carnwath Road,
       London, SW6 3EG,	UK.

       Copyright (C) 2000-2003 Richard Jones (	and other

       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
       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

perl v5.32.1			  2012-11-29		     Net::FTPServer(3)


Want to link to this manual page? Use this URL:

home | help