What is this? ============= This is a set of replacement source files for the popular Washington University enhanced FTP daemon, designed to fix bugs and increase security. Many sites are already running the current version 2.4 of this daemon because it is considered more flexible and secure than the stock FTP servers that vendors provide. It is also being included as the standard "ftpd" in several freeware Unix variants. But there are still several problems with WU-ftpd-2.4. Most serious, and this problem exists in virtually ALL FTP servers, is the ability for an anonymous user to make the server connect to an arbitrary port on an arbitrary machine and pass data in one direction or the other. This allows a whole variety of annoyance and denial-of-service attacks, and in some cases could allow unintended access to other machines. Selection of data ports has therefore been restricted in this version. Another problem is with the extensions to the program themselves. The "SITE" command has received particular attention as being a potential security hole. File access permission checks pass through a large and complex body of code that to this day is still not well-proven. Part of this replacement kit allows disabling this extra "extension" code for situations that don't need it -- notably, public FTP servers that organizations place out on the net for anyone to retrieve files from. Many of the extensions serve little or no purpose for public FTP servers, although they may be of some use to people inside an organization. This kit allows compile-time disabling of the more questionable parts of this extension code, and a default state of not using the rest of it. Optional support for S/Key has been added. Along the way, several outright bugs have been fixed, and some changes and new code from a prerelease "Debian" Linux release merged in. The exact changes to the package are detailed below. Please try to understand these changes, and why they are there, before using this package. Instructions: ============= Un-tar the original wu-ftpd-2.4 distribution. It creates a subdirectory for itself, wu-ftpd-2.4/. If you already have the source exploded somewhere else and planned on using that, it is actually safer to create a new tree from the original .tar.Z. CD into the wu-ftpd-2.4/ subdirectory. Un-tar the fix-kit. This replaces various files in the source tree. To see the modifications, un-tar the fix-kit into some other directory first and diff the trees. If you want to build in S/Key support, skip down to the "Building S/Key" section below. Figure out what kind of system you need to build for, by typing "./build help" and reading through the alternatives. Let's assume you pick "foo". Run the build script with a Magic Argument, by typing "./build fixed foo". The "fixed" argument causes the script to pause in the middle and give you a shell prompt. This is a bit of a kludge, but seems the least painful way to make this work without changing ALL the makefiles. This shell is in the src/ subdirectory, so edit Makefile and make any of the following changes: add -DPARANOID to CFLAGS to disable questionable functions. add -DANON_ONLY to CFLAGS if you're building an anonymous-only server. add -DSKEY to CFLAGS, and -lskey to LFLAGS, to add s/key support. Make sure skey.h is present in the src/ directory as well. If you REALLY want to use regular passwords, comment out the line mentioned in ftpd.c that normally disallows them. Arranging for static linking is recommended -- add whatever is appropriate for your site to LFLAGS. Write the changed file and exit the shell, and the build will continue and leave "ftpd" and related programs in both the src/ and bin/ subdirectories. [They are linked to each other, really.] If you want to build some different versions, for example with ANON_ONLY for your "outside" service and an S/Key enabled one for "inside", you don't need to run "build" again since you've already selected your Makefiles. It is faster to: cd to the src/ subdirectory change the Makefile as you wish make clean make Place your built "ftpd", or multiple instances thereof, wherever you normally keep the running daemon. Note that the functions of the -a, -l, and -L command line switches now defaults to TURNED OFF, so you may need to update your inetd.conf. The major change from the Debian release is the addition of the "noretrieve" keyword in the ftpaccess file; there is also an updated manpage describing it. Building S/Key: =============== You should be able to use any of the s/key distributions that let you build the "libskey.a" library. If you don't have one already, you should be able to get one from the same site you got this fix-kit. Build libskey.a. For Hobbit's kit, use "make ALL=libskey.a". Add "MD=5" to this if you want to build an MD5 version. Note that in this case is NOT the same as the systype argument to wu-ftpd "build"! For any other packages, see the instructions that come with them. Copy libskey.a to wu-ftpd-2.4/support, and skey.h to wu-ftpd-2.4/src. Go back up and continue with the main build instructions. Summary of changes: =================== Lifted from the Debian wu-ftpd-2.4-4 release with little or no change: doc/ftpaccess.5 doc/ftpd.8 config/config.lnx config/config.s41 src/access.c src/acl.c src/ftpcount.c src/ftpshut.c src/hostacc.c src/logwtmp.c build: added a kludge for enabling these changes, by spawning a shell. Added specific support for FreeBSD 2.0. Also, copy the Makefiles and config.h instead of hardlinking them, so that edits don't trash the original copies! support/authuser.c: limit sscanf() of identd strings. support/makefiles/*: minor changes to a couple of system-specific Makefiles. *NOTE: everything following is under src/. extensions.c: [Debian -- "noretrieve" ACL keyword handler, NULL fixups] extensions.c: Fix losing null dereference in Debian checknoretrieve(). extensions.c: #ifdef PARANOID -- disallow file deletion completely. ftpcmd.y: [Debian -- "bison" patch for linux just moved some decls around] ftpcmd.y: check PORT command against a bunch of things: being logged in, the client's source address, and the actual port number 1024 or greater. See discussion of ports below. ftpcmd.y: require login before various other things work: PASV, RNTO ftpcmd.y: #ifdef PARANOID -- disable, trap, and log all SITE commands. Comments withheld about the lineage of whoever cooked up *that* gem. ftpd.c: [Debian -- support "noretrieve" ACL keyword; misc NULL fixups] ftpd.c: preload assorted variables with reasonable values. Globalize guestpw and authuser and update them so all routines can access them for correct logging. ftpd.c: disallow "re-login". ftpd.c: #ifdef ANON_ONLY -- only allow anonymous logins. Designed for the ftpd you hang out on your external machine. ftpd.c: various places -- if told not to use the "ftpaccess" file, genuinely don't use routines that deal with it at all. [May save some of our butts when someone finds a bug in the extensions code!] ftpd.c: #ifdef SKEY, added s/key functionality. The challenge emerges where the "Password required for username" response is normally sent. ftpd.c: add endspent() to the shadow code, per Marek M. ftpd.c: Flag attempts to exploit the trojanized 2.2c version. ftpd.c: #ifdef STUPID_SPRINTF -- break up big "sprintf" for xferlog into two pieces. On some systems, sprintf is BROKEN. If you're using xferlog and your ftpd crashes right after a transfer, you probably need this. ftpd.c: #ifdef PARANOID, disable file overwriting, with either "put" or "rename". ftpd.c: Fix an ACL bug in renamefrom(). Doing two renames in a row would bypass the setting in the ACL file... ftpd.c: call realpath() to get current wd. ftpd.c: close data ports upon exiting, and close old PASV port if told to open a new one. See note below on ports. newvers.sh: include tiny little advertisement. makefiles/Makefile.lnx: Mostly Debian; add -static, remove -DDEBUG, put in the "bison fix". makefiles/Makefile.fbs: Add for FreeBSD 2.0; slight mod of "bsd". config/config.fbs: config.h for Freebsd 2.0. Contains a hack to work around the fact that freebsd stdlib.h comes with a realpath() and the define in ftpd.c conflicts with it. See note below about realpath(). config/config.lnx: Debian version, with the same realpath() hack added. Linux has trouble with this too, but in unistd.h. Put "realpath" back into SRCS and OBJS definitions. pathnames.linux: From Debian. Use this as a starting point for customizing pathnames.h on linux. A remaining deficiency is that NONE of the sources even *try* to reference the /usr/include/paths.h that many systems now have. Notes: ====== Per a security advisory in early June 1995, make SURE your definition of _PATH_EXECPATH is set to "/bin/ftp-exec" rather than "/bin" in whatever pathnames.h you wind up building with. This closes a potential "get-root" hole that is present in several Linux distributions. To be even more sure, prohibit any use of SITE commands. While looking for previously-done work for Linux compatibility, I ran across an improved distribution from the Debian tree on tsx-11.mit.edu. I have merged those changes into this code as listed above. Besides the "noretrieve" keyword, most of the Debian changes are NULL fixups, where NULL is properly changed to '\0' or 0. Various #includes of and/or have been moved out of individual source files and into config.h. If your ftp client has trouble with s/key, it may be because it truncates passwords to 8 characters before sending them to the server. SunOS "ftp" does this, for example. Get around this by using quoting: ftp> quote "user foobar" 331 [s/key 97 ts04745] required for foobar. ftp> quote "pass lays joke hum sear woo rail" 220 User foobar logged in. Many systems now have a library realpath() function, which conflicts with the one that comes with ftpd. However, the version that comes with ftpd is aware of its environment and briefly sets its effective UID to root to try and get its working directory. This is actually more useful if you have an "opaque" directory that is mode xx1 or xx3, because although trying to read or "ls" the directory will fail, ftpd can always determine where it is. The "opaque" directory is useful as a drop-off point for files intended for one recipient -- the name of the file is effectively a password for it. To avoid the compilation conflict, add "#define realpath realpath_on_steroids" to config.h and use the realpath() you have the source for. The supplied logwtmp() function doesn't work on Solaris and perhaps other SV variants. Swapping in Wietse Venema's sys4wtmp.c for logwtmp.c seems to do the trick. You can get this from his logdaemon package. I'm glad that *someone* understands this WTMPX idiocy, because I'm *still* having trouble with it. And every major vendor insists on doing it differently... There are MYRIAD possibilities for the port-bouncing attack. With a standard ftpd, anyone has at their disposal a TCP socket on a "reserved port", which some protocols are still relying on for security, and this socket can be connected to anywhere else on the net and data passed through [albeit only in one direction, goverened by use of STOR or RETR]. [It helps if there is a writeable directory on the server somewhere.] Consider these few examples. STORing a file from another machine's "chargen" port [or even the server's own port] will quickly fill the server's disk space. RETRing a file containing an SMTP transaction to someone's mailer port could allow fake mail that is virtually untraceable. Some rsh or rlogin implementations may be weak and accept connections from port 20, and some sites trust their firewall machines with r-access. Stuffing an arbitrary .tar.Z down someone's X port can't be too healthy. You can probably cook up a hundred other fun uses for this. The fix is to only allow PORT commands back to the client machine, and only on "high" ports. Those that would argue that this Breaks the Holy Protocol are invited to read the "fix-kit overview" and run whatever Holy FTP Server they prefer. Another problem was observed in the implementation of PASV. This command tells the server to open a listening port on its end, and expect the client to connect to it for data transfer. The problem was that once these sockets were opened for listen, they were never closed, although they would accept connections AND DATA anyway. A simple program to read the port numbers, connect to them, and fill the receive queues can easily crash the server machine when it runs out of network data buffers. PASV now cleans up after itself, and ftpd also closes these ports when it exits. You may need to put -DNO_MALLOC_PROTO in your chosen support/ Makefile, as well as refer to the note about "arpa/ftp.h" in the INSTALL document. Fixing this thing was a pain. A lot of it reads like a second-rate undergrad thesis, there is still plenty of sloppy code kicking around, configuration is clumsy, and little thought seems to have been given towards true portability. I've gone after what I consider important, and hope that someone else will pick up where I left off and make further improvements. The fact that Washington U allowed a trojanized version of this to creep into a MAJOR distribution site is a huge black mark on their record, as far as I'm concerned. Having looked at this code, and having observed significant cracking activity originating from some of their machines, I trust them even less now, despite their laudable efforts at maintaining an archive site. Take this for what it's worth to you; I'm just ranting at this point. Architecture considerations: ============================ The safest way to make things available to the net is to dedicated a machine to this task, and run FTP and Web servers there. The FTP server for such a machine should ideally be built ANON_ONLY and PARANOID and run without the swoopy extensions, but this can make maintenance difficult if several different people have to maintain the server. A workaround is to have an "opaque" writeable directory [mode 733] that maintainers can "bounce" files through and then manually copy to the right places with the right ownership. As the FTP daemon does in "anonymous" mode, a web server should also run in a chrooted environment. Some sites may not have this luxury of hardware, and one or two servers will be performing many functions. Or the users may demand the convenience of FTPing files "as themselves" instead of using the "bounce" scheme. In this case, the "outside" FTP daemon can continue as a "super-safe" version, but a different daemon built to permit real user logins can also be run on a different TCP port that is access-controlled for "inside" use only with a wrapper program. Most FTP client programs accept a port-number argument for the control connection, and only default to 21. If your FTP client doesn't support this, beat up your vendor. Both the FTP client and server normally use (controlport - 1) for the data connection, which makes setting up access control filters fairly easy. The access extensions are often used to control "exportability" of certain directories. Failing any other method, one may feel a need to run the "outside" server with the extensions enabled to provide this access control. Keeping "SITE" disabled with the PARANOID directive is still recommended. Please try to balance in your own mind the importance of keeping your own site secure, versus feeding the idiocy of ITAR. This is not to imply that the extensions are inherently insecure, it is to imply that export restrictions on software are stupid. Since the format of the ACL file is rather obtuse, an easily defensible "oversight" in its format can allow unrestricted access to beneficial things like crypto code. _H* 950612 v1.3