DLK FTP Daemon 0.9 03 May 2000 Donald King ================================= This software is Copyright (C) 2000 by Donald L. King. However, it may be distributed and modified freely, provided that my name remains attached to any programs or products derived from it. The following files are included with the program: README This file Makefile Handles the build process common.h.in Becomes common.h 5.man.in Becomes 5.man 8.man.in Becomes 8.man dlkftpd.help Database for the HELP command sample.conf Example configuration file dlkftpd.h Header file (common definitions) config.h Header file (user-config settings) util.c Source code (utility functions) parser.c Source code (config parser) main.c Source code (daemon parent code) child.c Source code (daemon child code) DLKFTPD is a compact, simple, and powerful FTP daemon. It was designed as an alternative to the relatively bulky, buggy, and undeservedly prolific wu.ftpd, the Washington University FTP Daemon. It was created with simplicity and security in mind. Unfortunately, the daemon is Linux-specific. I don't have access to any non-Linux Unixes at the moment, although I may install FreeBSD in the future and try it out there. I intend to autoconf it eventually, but for now you're on your own if you're not running Linux. Drop me a line if you get it running on a real Unix. Installation ------------ * Edit Makefile The major settings will be the installation path information. It is CRITICAL that you correctly set this information, since the information is built into the executable. Granted, you can override everything at runtime, but you generally don't want to do that. If your system needs other libraries or (more likely) doesn't use -lcrypt, you should also edit the LFLAGS line appropriately. You might also want to turn on some processor-specific optimization flags, which you can add to the CFLAGS line. * Edit config.h To disable a flag, change the line to "#undef FLAG". To enable it, change the line to "#define FLAG". DEBUG is not recommended unless you have a specific need for it. When loglevel is set to debug for a server compiled with this command, copious amounts of debugging information are sent to the logfile. This information may contain cleartext passwords, so be careful with this. FEAT_SHADOW should be turned on if you have shadow passwords. Most people do these days. If you know for certain that you don't use shadowing, turn this option off. FEAT_BADRANDOM is used only if you are running a non-GNU libc and your rand(3) function isn't very random in the low-order bits. Defining this makes random numbers (needed for various parts of the FTP protocol) more random, at the cost of using floating-point arithmetic every time a random number is needed. Even if your system has a flaky rand(3), you may want to leave this off for performance reasons, although random numbers are used fairly infrequently. * Compile and Install The following sequence of commands should do it: root@host:~/dlkftpd-0.9.0# make all root@host:~/dlkftpd-0.9.0# make install Configuration ------------- Take a look at the $(ETCDIR)/dlkftpd.conf.sample file to get a feel for the configuration file format, then do a "man 5 dlkftpd.conf" to read the fine print. Once you know what you want, create a dlkftpd.conf that does it. You may want to set "loglevel=info" until you are certain that things are configured properly. Next, test your configuration. Edit the config file, and comment out any lines starting with "host_". Then add the following lines somewhere under the "[ftpd]" section: host_explicit=1 host_allow=127.0.0.0/8 That command forces the FTP daemon to accept connections from localhost and to deny all others. Next, run $(BINDIR)/dlkftpd; if it prints out no messages, then it has successfully read the config file and daemonized itself. The daemon needs to run as root. Once the daemon is running, do a "cat $(VARDIR)/dlkftpd.log". The result should look similar to the following: [2000-05-05 12:14:52] [notice] FTP daemon is open for business, pid=789 Now test out your server. Point your FTP client at localhost and make sure that what you see is what you wanted. Log in as a permitted user. Try logging in as an account that should be disabled, like root. Prod around as anonymous to see if you can get to anything you shouldn't. Once you're satisfied that everything is set up properly, do a "kill -TERM " on the server to shut it down, then undo the changes mentioned earlier and restart the server. If something looks wrong, change the config file to fix the problem, then do a "kill -HUP " to force a reload. Now that everything is working OK, edit your system startup files to start the program with the rest of your network daemons. On Slackware systems, the ideal place is at the end of the /etc/rc.d/rc.inet2 script. On RedHat and other Linuces with SysVile init scripts, create a new script under /etc/init.d to start and stop the server, then add the appropriate start and stop links under /etc/rc.d. Bugs, Caveats, and To-Do's -------------------------- * The daemon forks a new child process for each incoming connection. This limits the ability of the daemon to deal with large numbers of parallel clients, but improves security since each child has its own UID/GID. * The LIST and NLST commands should (but don't) escape filenames in some way so that clients don't get confused by spaces or control characters in filenames. * The LIST and NLST commands don't support globbing. But that's not portable anyway, so don't do that. I may write my own simple (i.e. '*' and '?' only) globbing code in a future version. * The LIST and NLST commands ignore any leading parameter which starts with a hyphen. This is for compatibility with numerous clients which issue "LIST -L" commands or worse. Thus, one cannot get a listing of a directory whose name starts with a hyphen without a CWD command. * For SITE commands which operate on files, bad things may happen if a filename contains embedded whitespace. For all other commands, the daemon follows RFC 2640 semantics, except for embedded CRs and LFs. * The daemon cannot be run from inetd. Some would consider this a bonus. Regardless, there are currently no plans to support inetd-based operation. * The daemon does not utilize the TCP Wrappers configuration files, "hosts.allow" and "hosts.deny". Instead, the daemon uses a conceptually similar scheme that is configured entirely differently. * The daemon has no RFC 1413 (Identification Protocol) support, which would be useful tracking down mischief makers. * RFC 2228 (FTP Security Extensions) support would be nice. But, do *any* clients support it? And could I even export the result from the USA? * RFC 2640 (I18n of the File Transfer Protocol) support may eventually come. It will probably occur in a piece-by-piece fashion. Security Notes -------------- * As soon as the daemon has received the USER and PASS commands, it calls the setuid(2) and setgid(2) functions to permanently change its permissions. * The daemon has been checked carefully for buffer overflows. Most string manipulation uses dynamically allocated memory. * The daemon carefully splices apart and reassembles all paths provided by the client. There is zero possibility of an anonymous user accessing files outside of the virtual tree by using an "unusual" path, unless you insert a symbolic link. * The daemon never calls the exec(3) or system(3) families of functions. Thus, there is no reliance on external programs to "do the right thing".