AXL FTP Server


This server is Copyright 2001 by Michael Lecuyer. Please mail problems and suggestions to Michael.
The latest version is always available at  www.theorem.com.

Introduction:
The FTP server is written in Java which requires either the  Java Developer's Kit (JDK) or the  Java Runtime Environment (JRE). The server is 100% pure Java and has been tested under Windows 95/98/NT/2000, Linux 6.1 - 7.3, and Novell Netware 4.10/5.0 and requires Java 1.2 or better.  The server offers a flexible security structure as well as effective authentication methods, the most flexible and secure using a RADIUS server for authentication.  The distribution file contains a ftpserver.jar file.  The command to run the server might look something like this: java -cp ftpserver.jar com.theorem.ftp.ftpd.

java -jar ftpserver.jar [configuration directory]

Installation:
The server's path should be set to com.theorem.* in your JAVA Classpath setting.  If, for example, you're using CLASSPATH=c:\java, the server will reside in c:\java\com\theorem\ftp.

Some Inner Workings

Configuration changes (changes to FTP.CFG or DIR.CFG) are checked every 60 seconds. If a configuration change occurs all subsequent connections will feel the effects of the change, but current connections will be unaffected.

The configuration thread runs a lower priority that other threads. This may slow down configuration changes on a very busy system. There is notification in the log file when the configuration has been read..

New logons receive their home directories (if configured) upon login, and these home directory mappings are lost upon logout or disconnection.

If RADIUS authentication is used the Idle-Timeout configured on the RADIUS server can be applied to the client. This means difference people may be allotted different time outs, or a common timeout. This does not yet apply to anonymous clients.
 

Notes for Linux startup

Run this from /etc/rc.d/init.d (Redhat) as ftpd.  There is a script called 'javaps' available at Linux Java Process Status page. It's very useful when determining which process to kill.  Or just start it up in local.rc

Configuration:
There are two configuration files - FTP.CFG and DIR.CFG. The first, FTP.CFG, contains general configuration parameters while DIR.CFG contains the virtual directory and permissions set up. The SAMPLES directory has an example setup.



 

FTP.CFG:
This file's default location is the current directory where the FTP server is run.  An alternate directory may be specified on the command line: java com.theorem.ftp.ftpd c:\ftpdir. The contents of the file are simple assignments.  Comments may be specified by a leading ; or #.  Blank lines are ignored.

Built in authentication uses a plain text password file.  If you want something more aggressive you can define your own class.  Sample code for using the RADIUS protocol is in RadiusAuthenticate in the sample directory.
If you're not using a RADIUS server, but want to use a password file or your own password check class both are available. To use a simple name & password file comment out or remove at least the radius.server entry to disable and use the following configuration:

; Authentication may be done two ways.
; The native internal way is to use a plain text file of names and passwords.
; Clearly this is a security problem, but effective for demonstrations or for an anonymous
; server.
; The file contains comma delimited name/password lines: michael, java98
; To use this method you must provide a text file defined here.  If the next method of
; authentication is provided this directive will be ignored.
; The file resides in the configuration directory.
password.file = password.txt

; The alternative is to provide your own class to perform authentications.
; This is the second authentication method.
; If you have your own class to authenticate with and do not wish to use the
; two internal methods define yours here:
; password.class = com.theorem.ftp.samples.TestAuthenticate

You can use your own class to, let say, use LDAP to look up names and passwords. Examples of an authentication implementation are found in the samples directory.

The server port number defaults to 21.  If you need a different port number (to support multiple servers, or for another reason) you can modify the command port number.  The default data port will always be one less than the command port.

; Server port number
server.port = 21

The log file may be located anywhere. The default is called FTP.LOG and is in the current directory.

; Server log file.  This can be anywhere - records status and errors
server.logfile = ./ftpnote.log

; Server transfer log file.
; Traditional FTP logs compatible with FTP log analysis programs
server.xferlog = ./ftp.log

; You can log commands as they arrive. Sometimes this is useful if the other side is sending
; unusual commands or gets stuck. Yes or no.
server.logcommands = no

An inactivity timeout may be set for clients. If radius.timeout (above) is specified server.timeout will be used for anonymous logins only. Initially all logons are considered to be anonymous until logged in so make this value at least sufficient to logon. If the server.timeout is set to zero no timeout will occur.

; Server socket timeout in minutes.
server.timeout = 15

If you want a file to be displayed at login define it's name here.  It must be located in the same directory as the FTP.CFG file.

As clients move about the server's virtual directories you can arrange to display a file upon a directory change. This defines the name of the file to look for.  Usually this file will describe the contents of the directory and it's files.

; Display this file on a chdir if it exists.
server.display = 00_index.txt

The total number of connections (including anonymous connections) can be set. If this parameter is not given or is zero unlimited connections will be permitted.

connections.max=100

Anonymous login control is exercised here.  If the anonymous.allow parameter is missing the default is to deny anonymous logins.  If set to yes you can specify the maximum number of simultaneous anonymous logins. The default is zero anonymous logins.

anonymous.allow=yes
anonymous.max=10

If you need a class to track certain uploads and downloads you can create a class to follow this activity.
The FileReceipt class implementation (see the examples directory for FileCheck.java - a very simple implementation) can match and track files.  There are two methods called when a file is uploaded and downloaded.  FileReceipt.getBefore() is called before a file is downloaded, and FileReceipt.getAfter() is called after a file is successfully downloaded.  The getBefore method can deny a file's download by returning a standard FTP response string (e.g. 553 Requested action not taken.).

; An example of a FileReciept class.  This class is called when a file is up/downloaded
; to trigger some event.
filereceipt.class = com.theorem.ftp.examples.FileCheck


DIR.CFG:
This file controls the names of the virtual directories (the directories the client sees), the physical directories associated with them, and the permissions for access.

Groups are used to shorten a list of names into one name.  The special character '@' implies all real logon clients, i.e. those that have a name and password.  To put it another way this means everyone but Anonymous.  The format of the group statement is:  group ClassName ClassList.  An example would be:

group webauthors mjl fred susan
group temp @

Groups may not contain the '*' wild card.  Duplicates resulting from list expansions are safe to use.  Groups may contain other classes.  The next example, although it contains redundant names, is harmless:

class toomany temp @ webauthors mjl fred

The default virtual home directory must be defined and must exist as a physical directory.  This is the directory that the newly logged on client will find themselves. This is designated by assigning the virtual directory to a physical directory. It can be the same as another virtual directory setup. If "/" isn't defined it will be impossible to use CDUP or CWD .. to get back to the root.

The format is Virtual_Directory    Physical_Directory   Permission_List. The Virtual Directories are described in with UNIX style path separators, the Physical Directories are described in the local system's structure.

Note: It is not possible to specify a root directory as a physical directory.  While a number of UNIX ftp servers usually share the entire file system, unless portions are specifically excluded, more modern FTP services prefer to only present portions of their systems for security reasons.  This limitation discourages you from exposing too much of your system.  Therefore you cannot specify / C:/ *, but you must specify a virtual root, something like / C:/WINDOWS/TEMP *.

Permissions come in three varieties.

Not specifying any permission denies everyone access to the directory. Always specify mappings in the UNIX style (forward slashes). Physical paths will be corrected internal for your platform. Here's a short example:

; Set up a virtual directory of "/" as the apparent root using the physical directory of C:\PUB.  Anyone, including
; anonymous, has read permission.
/                                 C:\PUB     *

; The webmaster is the only client who may read/write to the web pages
/www.theorem.com  C:\WEB\DOCS +webmaster

; Michael may administer his web page, but the webmaster is denied.
/www.theorem.com/michael C:\WEB\DOCS\MJL +michael !webmaster

; Only Cynthia may write to her personal directory. No one else has access.
/users/cynthia          C:\PUB\CYNTHIA +cynthia

; The local directory is denied to anonymous even though the virtual directory "/" is accessible.
/local                          C:\PUB\LOCAL !anonymous

; The web authors class has free reign over this directory
/webpages                C:\WEB\DOCS +webauthors

; Everyone may write in /tmp, except anonymous
/tmp                            C:\TMP +@

Home directories are supported and are quite flexible. Multiple home directories may be defined both as shortcuts, and to provide multiple personal FTP directories. Each directory configuration has a name, A.user through Z.user. Each name specifies a physical directory. A string of "{}" within the physical directory will be substituted with the logon name. If the "{}" is missing it's appended to the physical directory. The resulting virtual directory will appear as "/user/{}/[subdirectory]". From the following example this will become clearer.  This is example is for Linux, on windows the paths will look like C:\although forward slashes are correctly handled under windows.

A.user = /user/{}/www>/FONT>
B.user = /user

This will result in two mappings when Michael logs in:

/user/michael/www   ---> SYS:/user/michael/www
/user/michael       ---> SYS:/user/michael

The logged in client will have full permissions to the directory (see below under DIR.CFG what this implies). Multiple mappings that result in the same virtual directory will only appear once. Always specify mappings in the UNIX style (forward slashes). Physical paths will be corrected internal for your platform.



 

WELCOME.TXT:
The WELCOME.TXT file (if it exists) contains a welcome message presented to each client as they successfully log on.  The file is in the same directory as the FTP.CFG file.


Directory Configuration Notes:

Setting the root directory  is very important, and the server won't run without one.  Preferably it should be set to a public directory and given public access:

    / /test *

Any virtual directory's contents will inherit the permission.   You may change permissions to particular directories by naming them:
; Set the root directory:
/ /test *
; Deny access to the source directory, except to michael
/test/source !* !@ michael

Denials: If you deny an entity, you must enable another if you want access to a directory.

  ; Deny anoymous but permit everyone logged in.
  /test /pub/test !anonymous @
or
  ; Deny michael access, but permit general access.
  /test /pub/test !michael *
or
  ; Deny anonymous but permit michael
  /test /pub/test !anonymous michael

The reason is that the FTP server can't determine who should have access '*' for public access or '@' for those actually logged in.

If you're having trouble accessing virtual directories check the log file - just after the server announces that it's started it prints a list of virtual directories and their permissions.  If a directory can't be accessed it'll say so too.


Programming Notes:

The code is divided into inner classes, each of which handles a particular FTP command (USER, CWD, STOR, etc).  n addition there are several sections:

CurrentInfo - holds current session information - the login name, directories  they have permissions to access (read only or read/write). This also contains  the methods necessary to check that the entity has permission which is done on  the fly.

Changing the configuration files - a separate thread periodically checks to see  if the configuration files have changed and makes those changes to the static  Global class. As each session starts it gets it's own copy of the Global class.

There are two other classes that may be implemented. One is a preferred authentication method, beyond the simple text file lookup. The other is a class is informed of attempts to access files for upload or download. You may control access more finely through this class (lets say you'll never let anyone get password files) or use it to notify other programs that a file has bee uploaded or downloaded.