Cover V03, I01
Figure 1
Figure 10
Figure 2
Figure 3
Figure 4
Figure 5
Figure 6
Figure 7
Figure 8
Figure 9
Sidebar 1


Configuring FTP

Arthur Messenger


The current version of the File Transfer Protocol (FTP) is defined in RFC 959, October 1985. Its purpose is to reliably transfer files between computing systems independent of the operating and storage systems.

FTP uses a client-server model. The server side is implemented by a daemon called ftpd or in.ftpd. The client side is implemented with a program called ftp. Figure 1 shows a simpified model of FTP.

The client starts the session by opening a control connection with the server, sending the request to port 21/tcp. The client sends its port number, and network address in the connection request. If ftp is not available at the network address, the transport provider returns a "connection refused message." If the request for a control connection is accepted, the ftp server sends back a reply code 220, saying that the server is ready, start the authentication process.

The reply code is a three-character digit code followed by a text string. The text string is for human use and is not fixed by the protocol. The digit code is used by the client process and is fixed by the FTP protocol. The first digit tells whether the reply is positive or negative. The second digit tells the reply's category. The third digit, if not 0, is a gradation of the reply. See Figure 2 for the meanings of the first two digits.

Once authentication is done and a confirming reply is returned, the client issues commands, and the server responds with replies on the control connection. RFC 959 contains a list of all client commands and server replies. I found that only a subset of the commands available under the FTP protocol are implemented.

If there is data to transfer, the server opens and manages a new connection to transfer the data. It uses port 20/tcp on its side of the connection. By default the client's control port and network address form the other half of the connection. The client can specify another port and network address by using the PORT command.

This paper reports on an exploration of the server side of the FTP protocol. I used three versions of UNIX: System V/386 Release 3.2 from Interactive (SVR3), System V Release 4.0 from Dell (SVR4), and Sun 4.1.3 from Sun Microsystem (SunOS).

Starting ftpd

On all three operating systems, ftpd does not listen for session requests. Instead inetd is configured to listen for requests. inetd executes ftpd once for each request received. If inetd is not listening for requests, when an ftp request comes in, the client receives a "connection refused" message from the transport provider.

I tried to run ftpd as a standalone program, mostly to see what would happen because the program is designed to work under inetd. I removed ftpd from inetd.conf. I logged in as root and started the ftpd program. In each case the program stopped executing with an error message showing there was a problem with its access to the network.

Options of ftpd

The last field of inetd.conf mimics starting the program from the command line. This allows the specification of options for the program. ftpd has three options:

  • -t, user inactivity time out;

  • -l, logging users to syslog; and

  • -d, logging debugging information to syslog.

    The -t option identifies the number of seconds of inactivity allowed before ftpd closes the session. Figure 3 shows the results of setting the -t option to 20 seconds on SVR4. The 421 time out reply code does not show on the screen until another command is issued. The default inactivity time is 900 seconds (15 minutes). The other systems' ftpds acted similarly.

    The -T option of SVR3's ftp program allows a user to override the -t option by specifying the timeout for this session. This has a maximum of two hours.

    ftpd writes three levels of messages to the syslog daemon facility. Figure 4 shows the levels and the types of messages. The err level messages are always written. The info level messages are written only if the -l option is set. The debug level messages are written only if the -d option is set. The syslog.conf file must be modified to direct messages or they are lost.

    While testing for the -l options, I found that ftpd writes login and logout information in the wtmp file. Usually, this information is sufficient. On DELL's SVR4 the wtmp records have an error and cannot be read by who. Here I do use the -l option.

    The data available from ftpd's -d option is difficult to correlate to the actions of the user of the ftp client. The same data available from ftpd's -d option is available from the client's ftp by using the verbose and -d option. The sidebar "A Sample ftp Session with the -d Option" walks you through a session with verbose and -d enabled.

    Configuration Files of ftpd

    Basic access to ftpd requires a user to be listed in the server's /etc/passwd file and to have a password. Anonymous ftp does not require a valid password in /etc/passwd. The files /etc/ftpusers and /etc/shells modify the basic requirements.

    The file /etc/ftpusers is a list of account names, one per line, that may not log into the system through ftp. I tried this on all systems, and it is true that you cannot login if your account name is in the file. However, this does not apply to anonymous ftp. David A. Curry, in UNIX System Security suggests:

    As a minimum, the super-user, root, and any other accounts with user id 0, should always be listed in this file. System accounts that do not normally have a human associated with them, such as bin, daemon, news, sync, sys, and uucp, should usually be listed as well. (page 70)

    For SVR3, the file /etc/shells determines which additional shells are allowed over the standard shells: /bin/sh, /bin/ksh, /bin/csh, /usr/bin/sh, /usr/bin/ksh, /usr/bin/csh.

    The SVR4 /etc/shells file works slightly differently. If the file does not exist, then only the standard shells sh, ksh, and csh in /bin and /usr/bin are allowed to login using ftp. If there is an /etc/shells file, then only accounts with a listed shell can use ftp. If the file is empty, then no one can use ftp.

    SunOS's /etc/shells file works similarly to the SVR4's except that it uses a different list of default shells: sh and csh in the directories /bin and /usr/bin.

    As a result of exploring the options and setup files for ftpd, I do the following when setting up ftpd: First, I use the timeout option (-t) with a value of 300 seconds -- five minutes is a long time for no activity. Second, I follow David Curry's recommendations on /etc/ftpusers and place all super-user accounts and all accounts not associated with an individual in the /etc/ftpusers. Third, I list all of the shells being used on the system in /etc/shells. I do not use the option -d. I only use the -l option on DELL's SVR4.

    Configuring an Anonymous ftp

    If the system administrator establishes an account named "ftp," ftpd will allow access to anyone who can ping the system using the account name "ftp" or "anonymous." Any set of characters works as the answer to the password question; just pressing the enter key does not work. This access method is generally referred to as "anonymous ftp."

    Each version of UNIX has a set of directions for setting up anonymous ftp. The emphasis here is on why the ftp account structure must have certain directories and files, and on the tools available to find the necessary directories and files.

    The first step is to make sure your ftpd does not have known bugs. This means having the current version of the software. I found that the only sure way to know what version of ftpd is being used is to talk with the vendor.

    In UNIX System Security, Curry talks about problems with versions of ftpd earlier than July 1989. Node in file /pub/NetBSD/NetBSD-current/src/libexec/ftpd/ftpd.c shows the current version to be 5.4 (Berkeley) 7/2/91. CERT advisory CA-93:06 shows the current version from to be 8 April 1993. Versions of ftpd based on the BSD software are probably safe if the version date is later than July 1989 and are probably the latest version if the version date is 2 July 1991 or later. The wuarchive version date should be after 8 April 1993.

    The second step is to create an account for the anonymous ftp. The structure, ownership, and permissions of the account are determined by three conditions. First, the account name must be ftp. Second, ftpd does chroot after accepting the password for the ftp account. Third, placement of the home directory is determined by the use of the account.

    An entry in /etc/passwd creates a new account. Figure 5 gives a summary of what is in the seven fields. The account name must be ftp. Since ftpd does not use the password entry, I usually keep it locked. The uid is any available user id. The group can be a default user's group. In the gcos field we place the words, "Anonymous ftp login." The location of the home directory can be any directory (placement of the directory is discussed in the section on downloading and uploading). The initial command field (shell) is not used, but I have seen the ftp program placed there. I tried /dev/null and it worked just fine. I normally place a non-executing file here, /noshell.

    The standard startup files are not necessary for this user. To handle mail that might come to this account, I add an entry to the aliases file, forwarding it to another user.

    The chroot command accepts a pathname as its only parameter. It changes the root directory (/), to this pathname. Only a uid 0 account can execute this command. (Note: for chroot(2) to be effective, the program must then do a chdir(2) to /. Otherwise, . will access the current local directory.)

    After executing chroot, the kernel does not allow access to any file outside of the local hierarchy, does not allow a cd outside of the local hierarchy, and does not allow symbolic links outside of the local hierarchy. Thus, a limited file system hierarchy must be built under the ftp account's home directory, the new /, to contain the files ftpd needs. The chroot command is executed as part of accepting the password. chroot restrictions are in force when the 230 reply code (230 "Guest login ok, access restrictions apply.") is displayed.

    The ftpd needs access to the ls command after the chroot to comply with the ftp protocol commands LIST and NLIST. The ls command is usually stored under /bin and /usr/bin. On all systems I looked at, the 150 reply code to an ftp dir or ftp ls command shows the path to the command being executed by ftpd. The reply shows ftpd using the ls in /bin. The limited hierarchy needs the directory ~ftp/bin to hold a copy of the ls command. The permissions on the command should be 111 since ftpd needs only to execute the command.

    The ls command depends on accessing dynamic libraries for some of its subroutines. In SVR4 and SunOS, the command ldd lists the dynamic libraries used by a command. SVR3 does not have the ldd command; the command dump with the -Lv options gives the same information. The dump command is also available on SVR4. Figure 6 shows the results on the different systems. The libraries are stored in /usr/lib on SVR4 and SunOS. On these systems, the ftp account needs the directory ~ftp/usr/lib with copies of the libraries. On SVR3 the library directory is /shlib. Here the ftp account needs the directory ~ftp/shlib and a copy of the library. All of the ls accessed libraries are needed since ls is accessed after the chroot. The libraries need the same protection as in the normal hierarchy, so permissions are 555.

    The command lld or dump must be run on the ftpd command since ftpd may access libraries after the chroot. Figure 6 shows the results on the diffent systems. I tested each library to see if it was needed. SVR3 is easy since both ftpd and ls need the same libraries. SVR4 shows that ftpd needs two additional libraries besides the one needed by ls. Experimentation shows neither library is needed. Under SunOS, a quick experiment accessing anonymous ftp without the library and with the library shows ftpd needs the /usr/lib/ and /usr/lib/ libraries. SunOS also needs the file /usr/lib/, the runtime loader. This file is needed anytime a dynamic library is used. When I leave it out, the error message shows this file is necessary.

    For the ls command to display the correct information it needs to access the files /etc/passwd and /etc/group. Strip these files of all entries that are not needed. The /etc/passwd file shows only the owners of files and directories. The /etc/group file shows only those groups associated with files and directories. In fact, the entries can be entirely bogus so long as the uids and gids match those in the ~ftp hierarchy. The files are stored in ~ftp/etc. The files need the same protection they have in the normal hierarchy; permissions are 444.

    Commands may access a device file during their execution. On SunOS, the command trace shows all system calls and signals for a command given as a parameter. grepping for /dev shows a superset of the devices needed. On SVR4 the output of the command truss, trace system calls and signals, can be greped for /dev to find all of the possible device files. On SVR3 neither trace nor truss exists, so I used strings, grepping for /dev. Figure 7 shows that the ls command accesses no device files in SVR3. Experimentation shows the only device file necessary in ~ftp/dev of all those listed by the strings command is tcp.

    grepping the SVR4 truss files for /dev, as shown in Figure 8, and doing some experimentation shows that ls needs /dev/zero and ftpd needs /dev/zero and /dev/tcp. The /dev/tcp is a STREAMS device file accessed whenever a tcp port is opened. In STREAMS on SVR4, multiple transport mechanisms are possible. The file /etc/netconfig contains information on available transport mechanisms. It is accessed whenever a STREAMS device is used to find the underlying transport mechanism. Thus, the file must be available in ~ftp/etc.

    grepping the SunOS trace files for /dev, as in Figure 9, shows ls needs the device /dev/zero and ftpd needs /dev/zero and /dev/null. Experimenting shows the /dev/null driver is not needed.

    The device files cannot be copied into ~ftp/dev. The file system entries must be made with the program mknod, which makes a special file using the same major and minor numbers for the corresponding device files in /dev. To find the major and minor numbers, do an ls -l on the device in /dev. If ls is derived from SVR3 or SVR4, then the major and minor numbers are the 5th and 6th fields of the output. If ls is derived from a BSD-based system, then the major and minor numbers are the 4th and 5th fields of the output.

    Figure 10 summarizes the directories, files, and their permissions needed in the ~ftp hierarchy. (Traditionally, there is one more directory. I discuss it in the Uploading and Downloading Directories section.)

    One question not decided is who should own the ~ftp hierarchy. CERT in Anonymous FTP Configuration Guidelines recommends that the ftp account's home directory and the subdirectories not be owned by ftp. This prevents anyone from making changes to the ~ftp hierarchy. Without recommending, CERT states that for most systems root is acceptable as the owner of the directories in the hierarchy, and whatever corresponds to root's group is good for the group of the hierarchy directories.

    Downloading and Uploading Directories

    One more directory, ~ftp/pub, is traditionally added. If the server will allow only downloading then the permissions on the directory are 755. It's under this directory that you should build the hierarchy used to hold the files clients are allowed to download.

    If uploading is allowed, create a directory, ~ftp/incoming, with the permissions set to 777 to allow anyone to create files in the directory. This opens up ftp to some abuses. Placing this directory in its own partition or, if possible, limiting the space available for the directory allows you to protect the system from some of the abuses.

    CERT, in Anonymous FTP Configuration Guidelines, suggests a method of hidden directories to limit access to uploading. To implement this, first change the permissions on ~ftp/incoming to 751. This allows the anonymous ftp user to change to the directory but not to list the contents of the directory. Second, create directory names using the same rules as making good password names. Give these subdirectories to ~ftp/incoming permissions 777. Now anyone knowing a subdirectory name can upload to the known directory. The security of this system is only as good as the password-directory names.

    Generally, I follow the directions given in the ftpd man page for setting up anonymous ftp. I modify the directions to follow CERT's suggestion on ownership of the files and directories. However, for each system I explored, I found I needed to use ldd or dump -Lv, and trace, truss, or strings to find missing data.


    RFC 959. J. Postel and J. Reynolds, October 1985. Available by anonymous ftp from host, directory /rfc, file rfc959.txt.

    UNIX System Laboratories. User's Reference Manual/System Administrator's Reference Manual for Intel Processors. Prentice Hall, 1992. ISBN 0-13- 951310-8.

    SunOS Reference Manual. Part Number:800-3827-10, Revision A of 27 March 1990.

    Anonymous FTP Configuration Guidelines. CERT. Available by anonymous ftp from host, directory /pub/tech_tips, file anonymous_ftp.

    Curry, David A. UNIX System Security. Addison-Wesley, 1993. ISBN 0-201- 56327-4.

    About the Author

    Arthur Messenger returned from the Air Force, where he worked on numerious computer systems, in 1988. Since then, he has been doing teaching and consulting. His current interest is in UNIX and Network management. He can be reached at