Subject: Whats new in the acad versions of wu-ftpd?

From: Somebody <[email-masked]>
Date: Mon, 4 Sep 1995 10:44:54 -0500 (CDT)

I was just wondering if someone can give a me a breakdown of whats
new wu-ftpd? And what advantages there are or disadvantages?
	What I am looking for is the following excuse my ignorange if 
this already exists and if so please send more details
	1) Basic Virtaul hosting for ftp space so that ftp.a.com starts in
	one location and ftp.b.com starts in another.
	2) Individual xferlogs for users
	3) Individual config file that will allow users to do the following
		a) decided what is max size there incoming can be and also
		obey a global config file. 
		b) yet still obey quotas
		c) decide what to log and what not to log.
		d) Possible there own motd
	4) a rate meter much like the current % but instead be K/s

	What mosts interests me is individual Incoming dirs.
					thanks for you attention.
						Carlos

---

From: "Ronald F. Guilmette" <[email-masked]>
Date: Mon, 04 Sep 1995 02:44:35 -0700

Greetings!

I have only just joined this list, so I hope you will all bear with me
while I get aquainted with y'all.

To introduce myself, I'd like to share with you all what I believe to be
a useful enhancement to the basic file transfer logging facilities pro-
vided by wu-ftpd 2.4.  But first let me describe why I implemented this
enhancement.

After many years of having access to the Internet via paid subscriptions
to various Internet Services Providers (I'm now on my fifth ISP) there
are a few things I've learned about ISPs.  One is that they all do things
differently from one another.  Another is that getting them to accomodate
the special needs of individual subscribers (like myself) is often difficult.
Even when you can get get them to agree that doing this or that to their
system configuration would cause no harm, it is often difficult to get
ISPs to make changes in a timely fashion.

Anyway, this general problem (of getting proper and timely individual
support from ISPs) hit home again for me recently, when I noticed that
my new ISP had their /usr/adm/xferlog file set so that it could only
be read by the super-user.  Given that I had (and still have) a serious
financial interest in monitoring who accesses the files I make available
for FTP (and how often), the un-readability of the /usr/adm/xferlog on
my new ISP's ftp server distressed me greatly, because it meant that I
would have no way of finding out who had accessed my ftp'able files.

That small problem has since been corrected by the ISP, but while I was
waiting for it to be corrected, I realized that there are a number of
other problems inherent in the idea of a single centralized FTP file
transfer logging file which is owned and controlled only by system
administrators.  The first of these is now obvious.  Unless the system
administrator(s) of your ISP is/are willing to let you do so, you, as
an individual end-user, will not even be able to read the log file.
Just as disturbing is the possibility that the system administrators
will not have even enabled file transfer logging, thus making it utterly
impossible for you, as an end user, to obtain records of transfers into
or out of your own personal anonymous FTP area.

Even assuming that you get lucky, and find a competent and accomodative
ISP where the sysadmins have FTP logging enabled, and where the log file
is itself readable by ordinary users, there are a number of other problems
that can still arise.  The most serious of these is that the sysadmins
are quite likely to zero-out the log file (e.g. by cat'ing /dev/null to it)
every so often as part of their normal system operation duties.  (This
_must_ be done from time to time or else the log file will grow without
bounds and suck up massive amounts of disk space.)  Unfortunately, sysadmins
are unlikely to be so helpful as to warn individual end users that they are
about to do this before they do it.  Thus, if you, as an end-user, are trying
to keep a log of all file-transfers involving your own FTP area, the only
way you can be assured of obtaining a complete log of all such transfers
is to stay logged on to your ISP's FTP server 24 hours a day, and monitor
the ISP's /usr/adm/xferlog minute-by-minute for new entries relating to
your own FTP-able files.  Obviously this is impractical, so it seems that
there is currently no method which is both workable and 100% reliable for
an ordinary end-user to obtain a _complete_ log of all FTP file transfers
involving his or her files or directories.

Another problem is that even if your ISP maintains a /usr/adm/xferlog file
and makes it readable to you, the process of extracting information from
that file (which may grow quite large) relating only to *your* particular
FTP'able files and/or directories can be both cumbersome and highly in-
efficient... especially in the case where you are forced to do your own
scanning of the /usr/adm/xferlog file on a frequent and repeated basis.

Even if we ignore all of the problems listed above, another potential
problem for end-users of the /usr/adm/xferlog information is that you,
as an end-user, might want to obtain _separate_ logs of the file transfer
operations which have taken place for various subsets of your own personal
FTP area... for example you might have two subdirectories in your own
top-level FTP area called `work' and `play' and you might want to obtain
separate file transfer logs for each of these two areas.

Anyway, after considering all of these problems, I came to the conclusion
that what was really needed was an enhanced FTP file transfer logging
facility which would be entirely controlable by ordinary end-users (without
the help or intervention of system administrators) and which would allow
for the selective collection of file transfer data relating _only_ to
individual, user-specified directories.

After coming to this conclusion, I went forth and implemented what I felt
would be a good solution to all of the problems I've mentioned above.
Naturally, I did so starting from the wu-ftpd 2.4 sources.  My implemen-
tation of the enhanced file transfer logging facility is included below
as a set of patches to the wu-ftp 2.4 distribution.  I will now describe
this new facility briefly.

In a nutshell, when using the modified wu-ftpd, users may create files
named .xferlog in any directory for which they wish to log all file
transfers.  Whenever it performs a file transfer operation, the modified
wu-ftpd checks to see if a file by the name of .xferlog exists either in
the directory containing the file being transferred or in any parent
directory of that directory.  If so, then a record of the file transfer
operation is appended to each such .xferlog file.  The records themselves
are identical in content and format to the records which ftpd normally
appends to /usr/adm/xferlog.  That's all there is to it.  It is really
a rather simple enhancement to wu-ftpd.

There are however several important security-related restrictions which
the modified wu-ftp applies to these .xferlog files.  First, the modified
wu-ftpd will only write log records to .xferlog files which are plain
files.  If it sees that someone has created a .xferlog file which is a
directory, a named pipe, a device file, or a symlink, the new ftpd will
simply refuse to append any log records to that particular .xferlog file.
Second, the new ftpd will also refuse to append log records to any .xferlog
files whose hard link count is greater than one.  Last but not least, the
new ftpd will refuse to append log records to any .xferlog file it finds
which is not owned by the same user who owns the directory in which the
 .xferlog file itself resides.

The first two of these restrictions are intended to prevent unscruplous
users from tricking ftpd into corrupting random/arbitrary system files
simply by making hard or soft links to them and calling the links `.xferlog'.
(Note that ftpd opens the .xferlog files when it is running with its
effective user ID set to `root', so without these restrictions, ftpd
could be tricked into appending to... and thereby corrupting... virtually
any file on the system.  The final restriction is intended simple to prevent
unauthorized users from creating _effective_ .xferlog files in world-writable
FTP directories (such as are commonly used for uploads).  Such files, if
permitted, could use up disk space in a directory whose owner doesn't want
to pay for the extra disk space overhead of carrying around a .xferlog file.
(Note that unauthorized users can still create .xferlog files in world-
writable directories, but unless they own the directories in question also,
these .xferlog files will never be appended to by ftpd, and thus will never
grow as a result of actions undertaken by ftpd.)

It is important to note that given this new logging facility, ftpd may
make log entries in *several* different .xferlog files for any given
(single) file transfer operation.  In such cases, all of the .xferlog
files so modified will lie along a path reaching from the directory
containing the file which was transferred up to the current root directory,
i.e. the `/' directory.  The fact that multiple .xferlog files may be
present at various levels of the directory hierarchy and that _all_ of
these files will be individually updated, as appropriate, to log any
individual file transfer operation means that (for example) a system
administrator could have a .xferlog file in the ~ftp/ directory (which
would log *all* transfers into or out of the anonymous FTP area) and
yet an end-user could have another .xferlog file (say for example a
~ftp/pub/rfg/.xferlog file) which would log just the file transfer
operations relating to files or subdirectories of the directory which
contains it, and the two would not interfere with one another, or affect
one another in any way.

Another inherent aspect of this enhanced logging scheme that should be
appealing to system administrators and ISPs is that the space used by
any .xferlog files which are created by any given user is itself allocated
in FTP directories which are owned by that user.  Thus, this facility
provides no `freebies' with respect to disk space accounting.  If a
user creates a .xferlog file, then the space it occupies will be charged
against that user's disk space quota.

I hope that the subscribers to this mailing list will review my work on
this enhancement to wu-ftpd 2.4 and offer whatever comments, suggestions,
or criticisms seem appropriate.  My hope is to incorporate any feedback
I receive from the subscribers of this mailing list into the implementa-
tion of this enhancement, and then to offer (or post) copies of the final
patches to a wider audience (e.g. in various relevant newgroups).

Ron Guilmette
Infinite Monkeys & Co.

P.S.  In addition to the implementation of the logging enhancement de-
scribed above, the following patches also correct a number of other very
minor problems I discovered while working on the wu-ftpd 2.4 sources.
Most of these relate to building and/or installing wu-ftpd 2.4 under
Solaris 2.4.

diff -rc2 2.4-/INSTALL 2.4+/INSTALL
*** 2.4-/INSTALL	Fri Apr  1 11:03:58 1994
--- 2.4+/INSTALL	Sun Sep  3 22:35:28 1995
***************
*** 40,44 ****
      users, create a symbolic link from ~ftp/_PATH_EXEC to /_PATH_EXEC.
  
! 2a. build xxx
  
      where xxx is one of:
--- 40,44 ----
      users, create a symbolic link from ~ftp/_PATH_EXEC to /_PATH_EXEC.
  
! 2a. ./build xxx
  
      where xxx is one of:
***************
*** 85,89 ****
      Edit the three files appropriately.  Go back to step 2a.
  
! 3.  build install
  
  4.  edit /etc/inetd.conf to point to the new ftpd
--- 85,94 ----
      Edit the three files appropriately.  Go back to step 2a.
  
! 3a.  Edit the Makefile in the top-level directory and set the values of
!      `BINDIR', `ETCDIR', and `MANDIR', as seems appropriate for your system.
! 
! 3b.  Become super-user and then do:
! 
! 	./build install
  
  4.  edit /etc/inetd.conf to point to the new ftpd
diff -rc2 2.4-/Makefile 2.4+/Makefile
*** 2.4-/Makefile	Fri Apr  1 11:03:58 1994
--- 2.4+/Makefile	Sun Sep  3 22:34:04 1995
***************
*** 1,6 ****
  BINDIR=		/usr/local/bin
  ETCDIR=		/usr/local/etc
  MANDIR=		/usr/local/man
- MANEXT=		8
  
  all:
--- 1,10 ----
+ # The following definition might get overridden (with /usr/ucb/install) by
+ # the build script.
+ INSTALL=	install
+ #INSTALL=	/usr/ucb/install
+ 
  BINDIR=		/usr/local/bin
  ETCDIR=		/usr/local/etc
  MANDIR=		/usr/local/man
  
  all:
***************
*** 10,25 ****
  install: bin/ftpd bin/ftpcount bin/ftpshut
  	-mv -f ${ETCDIR}/ftpd ${ETCDIR}/ftpd-old
  	@echo Installing binaries.
! 	install -o bin -g bin -m 755 bin/ftpd ${ETCDIR}/ftpd
! 	install -o bin -g bin -m 755 bin/ftpshut ${BINDIR}/ftpshut
! 	install -o bin -g bin -m 755 bin/ftpcount ${BINDIR}/ftpcount
! 	install -o bin -g bin -m 755 bin/ftpwho ${BINDIR}/ftpwho
  	@echo Installing manpages.
! 	install -o bin -g bin -m 755 doc/ftpd.8 ${MANDIR}/man8/ftpd.8
! 	install -o bin -g bin -m 755 doc/ftpcount.1 ${MANDIR}/man1/ftpcount.1
! 	install -o bin -g bin -m 755 doc/ftpwho.1 ${MANDIR}/man1/ftpwho.1
! 	install -o bin -g bin -m 755 doc/ftpshut.8 ${MANDIR}/man8/ftpshut.8
! 	install -o bin -g bin -m 755 doc/ftpaccess.5 ${MANDIR}/man5/ftpaccess.5
! 	install -o bin -g bin -m 755 doc/ftphosts.5 ${MANDIR}/man5/ftphosts.5
! 	install -o bin -g bin -m 755 doc/ftpconversions.5 ${MANDIR}/man5/ftpconversions.5
! 	install -o bin -g bin -m 755 doc/xferlog.5 ${MANDIR}/man5/xferlog.5
--- 14,35 ----
  install: bin/ftpd bin/ftpcount bin/ftpshut
  	-mv -f ${ETCDIR}/ftpd ${ETCDIR}/ftpd-old
+ 	-mkdir ${ETCDIR}
+ 	-mkdir ${BINDIR}
+ 	-mkdir ${MANDIR}
+ 	-mkdir ${MANDIR}/man1
+ 	-mkdir ${MANDIR}/man5
+ 	-mkdir ${MANDIR}/man8
  	@echo Installing binaries.
! 	$(INSTALL) -o bin -g bin -m 755 bin/ftpd ${ETCDIR}/ftpd
! 	$(INSTALL) -o bin -g bin -m 755 bin/ftpshut ${BINDIR}/ftpshut
! 	$(INSTALL) -o bin -g bin -m 755 bin/ftpcount ${BINDIR}/ftpcount
! 	$(INSTALL) -o bin -g bin -m 755 bin/ftpwho ${BINDIR}/ftpwho
  	@echo Installing manpages.
! 	$(INSTALL) -o bin -g bin -m 644 doc/ftpd.8 ${MANDIR}/man8/ftpd.8
! 	$(INSTALL) -o bin -g bin -m 644 doc/ftpcount.1 ${MANDIR}/man1/ftpcount.1
! 	$(INSTALL) -o bin -g bin -m 644 doc/ftpwho.1 ${MANDIR}/man1/ftpwho.1
! 	$(INSTALL) -o bin -g bin -m 644 doc/ftpshut.8 ${MANDIR}/man8/ftpshut.8
! 	$(INSTALL) -o bin -g bin -m 644 doc/ftpaccess.5 ${MANDIR}/man5/ftpaccess.5
! 	$(INSTALL) -o bin -g bin -m 644 doc/ftphosts.5 ${MANDIR}/man5/ftphosts.5
! 	$(INSTALL) -o bin -g bin -m 644 doc/ftpconversions.5 ${MANDIR}/man5/ftpconversions.5
! 	$(INSTALL) -o bin -g bin -m 644 doc/xferlog.5 ${MANDIR}/man5/xferlog.5
diff -rc2 2.4-/build 2.4+/build
*** 2.4-/build	Fri Apr  1 11:03:59 1994
--- 2.4+/build	Sun Sep  3 22:30:16 1995
***************
*** 69,75 ****
--- 69,78 ----
          echo "Linking Makefiles."
  		cd src
+ 		rm -f Makefile
  		ln makefiles/Makefile.$maketarget Makefile
+ 		rm -f config.h
  		ln config/config.$maketarget config.h
  		cd ../support
+ 		rm -f Makefile
  		ln makefiles/Makefile.$maketarget Makefile
          echo ''
***************
*** 127,131 ****
  
      install)
!         make -f Makefile $makeargs $makeopts install
          ;;
  
--- 130,138 ----
  
      install)
! 	if [ -x /usr/ucb/install ] ; then \
!             make -f Makefile INSTALL=/usr/ucb/install $makeargs $makeopts install;
! 	else \
!             make -f Makefile $makeargs $makeopts install;
! 	fi
          ;;
  
diff -rc2 2.4-/doc/ftpd.8 2.4+/doc/ftpd.8
*** 2.4-/doc/ftpd.8	Fri Apr  1 11:03:25 1994
--- 2.4+/doc/ftpd.8	Sun Sep  3 22:23:04 1995
***************
*** 113,119 ****
  If the
  .B \-i
! option is specified, files received by the
  .IR ftpd (8)
! server will be logged to the
  .IR xferlog (5).
  The
--- 113,119 ----
  If the
  .B \-i
! option is specified, files transmitted or received by the
  .IR ftpd (8)
! server will be logged to the system-wide
  .IR xferlog (5).
  The
***************
*** 230,235 ****
  anonymous ftp account must be present in the password
  file (user ``ftp'').  In this case the user is allowed
! to log in by specifying any password (by convention this
! is given as the client host's name).
  .PP
  In the last case, 
--- 230,236 ----
  anonymous ftp account must be present in the password
  file (user ``ftp'').  In this case the user is allowed
! to log in by specifying any password.  (By convention, the
! remote user is asked to provide his E-mail address, but this
! is not checked or verified in any way.)
  .PP
  In the last case, 
***************
*** 317,320 ****
--- 318,397 ----
          1   RFC931 Authentication
   13 authenticated user id (if available, '*' otherwise)
+ .PP
+ File transfers may be logged to the system-wide
+ .I xferlog
+ file under the control of the 
+ .B \-i
+ option or the
+ .I "log transfer"
+ subcommand of the
+ .IR ftpaccess (5)
+ configuration file.
+ .PP
+ Separately, each file transfer may also be logged to one or more
+ .I \&.xferlog
+ files
+ if such files exist either in the same directory as the file being
+ transferred, or in parent directories of that directory.  In effect, each
+ .I \&.xferlog
+ file ``covers'' all of the files and subdirectories of the directory where
+ it resides.  If multiple
+ .I \&.xferlog
+ files cover a given file, then each of these
+ .I \&.xferlog
+ files will receive a log entry for each transfer of the file in question.
+ Note that the
+ file permissions of
+ .I \&.xferlog
+ files have no effect upon their use for file transfer logging because
+ these files are opened by the
+ .I ftpd
+ daemon when it is operating as
+ .IR root ,
+ which gives it unlimited permissions to open and write these log files.
+ Thus,
+ .I \&.xferlog
+ files may be set to any mode and logging to
+ them will still occur.  Note also that in the special case of
+ file transfers initiated by the anonymous FTP user,
+ .I ftpd
+ will only search for applicable
+ .I \&.xferlog
+ files up to the directory which is at the top of the logical filesystem
+ for the anonymous FTP user, i.e. the home directory of the user-id `ftp'.
+ No
+ .I \&.xferlog
+ files above that point in the actual filesystem will ever
+ be used to log file transfers initiated by anonymous FTP users.
+ .PP
+ Three special security-related restrictions apply to all
+ .I \&.xferlog
+ files used by
+ .I ftpd
+ for file transfer logging.  First, each
+ .I \&.xferlog
+ file must be a plain file.  It cannot be a directory file, a device file,
+ a named pipe, or a symbolic link.  Second, each
+ .I \&.xferlog
+ file must appear at only one place in the filesystem, i.e. its hard
+ link count must be exactly 1.  Lastly, each
+ .I \&.xferlog
+ file must be owned by the same user who owns the directory which contains
+ it.  If any one of these three conditions is not satisfied for a given
+ .I \&.xferlog
+ file, then
+ .I ftpd
+ will avoid doing any logging to the
+ .I \&.xferlog
+ file in question.  These conditions, taken together, insure that the
+ .I \&.xferlog
+ logging facility
+ will not be accidentally or intentionally misused in such a way as to
+ cause
+ .I ftpd
+ to corrupt other user files or to use disk space for
+ .I \&.xferlog
+ files in any directory where the directory owner did not
+ desire that such space be used.
  .SH "SEE ALSO"
  .MS ftp 1 ,
***************
*** 333,334 ****
--- 410,430 ----
  possible security holes have been extensively
  scrutinized, but are possibly incomplete.
+ .PP
+ The use of a
+ .I \&.xferlog
+ file in a publically-writable directory (such as a public upload directory)
+ can be problematic because the writability of the directory
+ will ordinarily make it possible for any user to delete an
+ .I \&.xferlog
+ file which resides therein.  Fortunately, this problem may be averted on
+ most current incarnations of UNIX by simply setting the sticky-bit on
+ such directories, and my making the
+ .I \&.xferlog
+ file in question non-writable to anyone but the original owner.  These two
+ steps will often prevent unauthorized users from deleting
+ .I \&.xferlog
+ files that they don't own, even in world-writable directories.  But
+ check your local
+ .IR chmod (2),
+ manpage to see if your system actually implements these semantics for
+ sticky-bits on directories.
diff -rc2 2.4-/src/ftpcmd.y 2.4+/src/ftpcmd.y
*** 2.4-/src/ftpcmd.y	Wed Apr 13 14:02:56 1994
--- 2.4+/src/ftpcmd.y	Sat Sep  2 10:29:14 1995
***************
*** 107,111 ****
  char    *fromname;
  
! static void toolong();
  
  %}
--- 107,111 ----
  char    *fromname;
  
! static void toolong(int);
  
  %}
***************
*** 1028,1032 ****
  
  static void
! toolong()
  {
      time_t now;
--- 1028,1032 ----
  
  static void
! toolong(int sig)
  {
      time_t now;
diff -rc2 2.4-/src/ftpd.c 2.4+/src/ftpd.c
*** 2.4-/src/ftpd.c	Wed Apr 13 14:17:18 1994
--- 2.4+/src/ftpd.c	Sun Sep  3 22:40:22 1995
***************
*** 60,64 ****
  
  #define FTP_NAMES
! #include <arpa/ftp.h>
  #include <arpa/inet.h>
  #include <arpa/telnet.h>
--- 60,64 ----
  
  #define FTP_NAMES
! #include "ftp.h"
  #include <arpa/inet.h>
  #include <arpa/telnet.h>
***************
*** 1236,1239 ****
--- 1236,1415 ----
  }
  
+ static void
+ log_xfer(int xferlog, time_t start_time, char *name,
+ 	 int options, int xfer_type, char *logname)
+ {
+     if (xferlog) {
+         char msg[MAXPATHLEN];
+ 	char namebuf[MAXPATHLEN];
+         int xfertime = time(NULL) - start_time;
+         time_t curtime = time(NULL);
+         int loop;
+ 
+         if (!xfertime)
+             xfertime++;
+         realpath(logname ? logname : name, namebuf);
+         for (loop = 0; namebuf[loop]; loop++)
+             if (isspace(namebuf[loop]) || iscntrl(namebuf[loop]))
+                 namebuf[loop] = '_';
+         sprintf(msg, "%.24s %d %s %d %s %c %s %c %c %s ftp %d %s\n",
+                 ctime(&curtime),
+                 xfertime,
+                 remotehost,
+                 byte_count,
+                 namebuf,
+                 (type == TYPE_A) ? 'a' : 'b',
+                 opt_string(options),
+                 xfer_type,
+                 anonymous ? 'a' : 'r',
+                 anonymous ? guestpw : pw->pw_name,
+                 authenticated,
+                 authenticated ? authuser : "*"
+             );
+         write(xferlog, msg, strlen(msg));
+     }
+ }
+ 
+ static void
+ write_dot_xferlogs(time_t start_time, char *name, int options,
+ 		   int xfer_type, char *logname)
+ {
+     char buf[MAXPATHLEN + 1];
+ #ifdef HAVE_GETCWD
+     extern char *getcwd(char *, size_t);
+ #else
+     extern char *getwd(char *);
+ #endif  
+ 
+ #ifdef HAVE_GETCWD
+     if (getcwd(buf,MAXPATHLEN) == (char *) NULL) {
+ 	syslog(LOG_ERR, "Error getting current directory: %s", strerror(errno));
+ 	return;
+     }
+ #else
+     if (getwd(buf) == (char *) NULL) {
+ 	syslog(LOG_ERR, "Error getting current directory: %s", buf);
+ 	return;
+     }
+ #endif
+ 
+     if (buf[0] != '/') {
+ 	syslog(LOG_ERR, "Current directory name does not begin with /");
+ 	return;
+     }
+ 
+     {
+ 	register int cwd_len;
+ 
+ 	cwd_len = strlen(buf);
+ 	if ((cwd_len + 1 + strlen(name)) > (unsigned) MAXPATHLEN) {
+ 	    return;
+ 	}
+ 	buf[cwd_len] = '/';
+ 	strcpy(&buf[cwd_len+1], name);
+     }
+ 
+     {
+ 	register char *slash = buf + strlen (buf);
+ 	register uid_t oldid;
+ 	register int xferlog;
+ 	struct stat st_dir;
+ 	struct stat st_file;
+ 
+ 	oldid = geteuid ();
+ 	seteuid ((uid_t) 0);
+ 	/* Do the scan for .xferlog files, starting at the directory con-
+ 	   taining the file to be transferred, and moving up the directory
+ 	   hierarchy until we reach the current root directory.  */
+ 	do {
+ try_again:
+ 	    *slash = '\0';
+ 	    while (*--slash != '/')
+ 		continue;
+ 	    if ((slash - 2) >= buf
+ 		&& slash[-1] == '.' && slash[-2] == '/') {
+ 		/* Skip over /./ parts, when present.  */
+ 		slash -= 2;
+ 	    }
+ 	    if ((slash - 4) >= buf
+ 		&& slash[-1] == '.' && slash[-2] == '.' && slash[-3] == '/') {
+ 		/* Skip over dirname/../ parts, when present.  */
+ 		slash -= 3;
+ 		goto try_again;
+ 	    }
+ 	    slash[1] = '\0';
+ 	    if (((slash-buf)+1+strlen(".xferlog")) > (unsigned) MAXPATHLEN) {
+ 		/* We may not be able to generate _this_ full pathname,
+ 		   but that should not stop us from trying to make
+ 		   entries in other applicable .xferlog files.  */
+ 		syslog(LOG_NOTICE, "Filename too long: %s.xferlog", buf);
+ 		continue;
+ 	    }
+ 	    if (stat(buf, &st_dir) == -1) {
+ 		/* If this directory is un-stat-able for some reason, skip
+ 		   it, but log an error to the syslog file.  */
+ 		syslog(LOG_ERR, "stat(2) yields error for dir %s: %s",
+ 			buf, strerror(errno));
+ 		continue;
+ 	    }
+ 	    strcpy(slash+1, ".xferlog");
+ 	    if (lstat(buf, &st_file) == -1) {
+ 		if (errno != ENOENT)
+ 		    syslog (LOG_ERR, "lstat(2) yields error for file %s: %s",
+ 				buf, strerror(errno));
+ 		/* If this .xferlog file doesn't exist or is un-stat-able for
+ 		   some reason, just skip it.  */
+ 		continue;
+ 	    }
+ 	    /* The .xferlog file must be a plain file.  End of story.  We
+ 	       don't allow the .xferlog files to be symlinks or directories
+ 	       or device files (or anything else weird) for security reasons.
+ 	       It might be interesting and/or useful to allow them to be
+ 	       named pipes, but we don't allow that either.  Note that we
+ 	       disallow both symlinks and hard links (see below) for the
+ 	       .xferlog files as a way of preventing unscruplous users from
+ 	       creating .xferlog files which are just links (of some kind)
+ 	       to other files owned by somebody else, and thereby inducing
+ 	       ftpd to corrupt those other files (by appending xferlog entries
+ 	       to them).  */
+ 	    if ((st_file.st_mode & S_IFMT) != S_IFREG) {
+ 		syslog(LOG_INFO, "Not a regular file: %s", buf);
+ 		continue;
+ 	    }
+ 	    /* We don't allow the .xferlog file to be a hard link to anything
+ 	       else.  This is also for security reasons.  (See above.)  */
+ 	    if (st_file.st_nlink > 1) {
+ 		syslog(LOG_INFO, "Too many hard links: %s", buf);
+ 		continue;
+ 	    }
+ 	    /* Last but not least, check that the .xferlog file is owned by
+ 	       the same user who owns the containing directory.  If it isn't
+ 	       then we won't use it for logging.  This is also a security
+ 	       feature.  It _should_ prevent unscruplous users from creating
+ 	       useable .xferlog files in other people's FTP directories
+ 	       (e.g. in world-writable upload directories)... at least that
+ 	       is the effect it will have on any well-run modern flavor of
+ 	       UNIX under which non-privledged users are not allowed to
+ 	       `chown' files to transfer ownership to other users.  Note
+ 	       that if we didn't impose this extra condition on .xferlog
+ 	       files, the only bad effect would be that users could po-
+ 	       tentially create .xferlog files in directories whose owners
+ 	       would prefer not to have .xferlog logging take place (perhaps
+ 	       because they don't want to pay for the disk space required).  */
+ 	    if (st_file.st_uid != st_dir.st_uid) {
+ 		syslog(LOG_INFO, "Not owned by directory owner: %s", buf);
+ 		continue;
+ 	    }
+ 	    if ((xferlog = open(buf, O_WRONLY | O_APPEND)) != -1)
+ 		log_xfer(xferlog,start_time,name,options,xfer_type,logname);
+ 	    else if (errno != ENOENT)
+ 		syslog(LOG_ERR, "Error opening logging file %s: %s",
+ 			buf, strerror (errno));
+ 	} while (slash > buf);
+ 	/* Done making entries in all applicable .xferlog files.  */
+ 	seteuid (oldid);
+     }
+ }
+ 
  retrieve(char *cmd, char *name)
  {
***************
*** 1411,1441 ****
  
    dolog:
!     if (log_outbound_xfers && xferlog && (cmd == 0)) {
!         char msg[MAXPATHLEN];
!         int xfertime = time(NULL) - start_time;
!         time_t curtime = time(NULL);
!         int loop;
! 
!         if (!xfertime)
!             xfertime++;
!         realpath(logname ? logname : name, namebuf);
!         for (loop = 0; namebuf[loop]; loop++)
!             if (isspace(namebuf[loop]) || iscntrl(namebuf[loop]))
!                 namebuf[loop] = '_';
!         sprintf(msg, "%.24s %d %s %d %s %c %s %c %c %s ftp %d %s\n",
!                 ctime(&curtime),
!                 xfertime,
!                 remotehost,
!                 byte_count,
!                 namebuf,
!                 (type == TYPE_A) ? 'a' : 'b',
!                 opt_string(options),
!                 'o',
!                 anonymous ? 'a' : 'r',
!                 anonymous ? guestpw : pw->pw_name,
!                 authenticated,
!                 authenticated ? authuser : "*"
!             );
!         write(xferlog, msg, strlen(msg));
      }
      data = -1;
--- 1587,1594 ----
  
    dolog:
!     if ((cmd == 0)) {
! 	if (log_outbound_xfers)
! 	    log_xfer(xferlog, start_time, name, options, 'o', logname);
! 	write_dot_xferlogs (start_time, name, options, 'o', logname);
      }
      data = -1;
***************
*** 1514,1518 ****
          trunc = 0;
  
!     /* if the user has an explicit new file mode, than open the file using
       * that mode.  We must take care to not let the umask affect the file
       * mode.
--- 1667,1671 ----
          trunc = 0;
  
!     /* if the user has an explicit new file mode, then open the file using
       * that mode.  We must take care to not let the umask affect the file
       * mode.
***************
*** 1598,1630 ****
  
    dolog:
!     if (log_incoming_xfers && xferlog) {
!         char namebuf[MAXPATHLEN],
!           msg[MAXPATHLEN];
!         int xfertime = time(NULL) - start_time;
!         time_t curtime = time(NULL);
!         int loop;
! 
!         if (!xfertime)
!             xfertime++;
!         realpath(name, namebuf);
!         for (loop = 0; namebuf[loop]; loop++)
!             if (isspace(namebuf[loop]) || iscntrl(namebuf[loop]))
!                 namebuf[loop] = '_';
!         sprintf(msg, "%.24s %d %s %d %s %c %s %c %c %s ftp %d %s\n",
!                 ctime(&curtime),
!                 xfertime,
!                 remotehost,
!                 byte_count,
!                 namebuf,
!                 (type == TYPE_A) ? 'a' : 'b',
!                 opt_string(0),
!                 'i',
!                 anonymous ? 'a' : 'r',
!                 anonymous ? guestpw : pw->pw_name,
!                 authenticated,
!                 authenticated ? authuser : "*"
!             );
!         write(xferlog, msg, strlen(msg));
!     }
      data = -1;
      pdata = -1;
--- 1751,1757 ----
  
    dolog:
!     if (log_incoming_xfers)
! 	log_xfer(xferlog, start_time, name, 0, 'i', NULL);
!     write_dot_xferlogs(start_time, name, 0, 'i', NULL);
      data = -1;
      pdata = -1;
***************
*** 2303,2307 ****
      char path[MAXPATHLEN + 1];
  #ifdef HAVE_GETCWD
!     extern char *getcwd();
  #else
      extern char *getwd(char *);
--- 2430,2434 ----
      char path[MAXPATHLEN + 1];
  #ifdef HAVE_GETCWD
!     extern char *getcwd(char *, size_t);
  #else
      extern char *getwd(char *);
***************
*** 2310,2317 ****
  #ifdef HAVE_GETCWD
      if (getcwd(path,MAXPATHLEN) == (char *) NULL)
  #else
      if (getwd(path) == (char *) NULL)
  #endif
-         reply(550, "%s.", path);
      else
          reply(257, "\"%s\" is current directory.", path);
--- 2437,2445 ----
  #ifdef HAVE_GETCWD
      if (getcwd(path,MAXPATHLEN) == (char *) NULL)
+         perror_reply(550, "Error getting current directory");
  #else
      if (getwd(path) == (char *) NULL)
+         reply(550, "Error getting current directory: %s.", path);
  #endif
      else
          reply(257, "\"%s\" is current directory.", path);
diff -rc2 2.4-/src/makefiles/Makefile.sol 2.4+/src/makefiles/Makefile.sol
*** 2.4-/src/makefiles/Makefile.sol	Fri Apr  1 11:03:28 1994
--- 2.4+/src/makefiles/Makefile.sol	Sun Sep  3 22:42:49 1995
***************
*** 2,6 ****
  IFLAGS   = -I.. -I../support
  LFLAGS   = -L../support
! CFLAGS   = -g -DDEBUG ${IFLAGS} ${LFLAGS}
  LIBES    = -lsupport -lsocket -lnsl -lgen
  LIBC     = /lib/libc.a
--- 2,6 ----
  IFLAGS   = -I.. -I../support
  LFLAGS   = -L../support
! CFLAGS   = -O -DDEBUG ${IFLAGS} ${LFLAGS}
  LIBES    = -lsupport -lsocket -lnsl -lgen
  LIBC     = /lib/libc.a
diff -rc2 2.4-/src/newvers.sh 2.4+/src/newvers.sh
*** 2.4-/src/newvers.sh	Wed Apr 13 11:41:33 1994
--- 2.4+/src/newvers.sh	Sat Sep  2 10:31:06 1995
***************
*** 20,23 ****
--- 20,24 ----
  if [ ! -r edit ]; then echo 0 > edit; fi
  touch edit
+ rm -f vers.c
  awk '	{	edit = $1 + 1; }\
  END	{	printf "char version[] = \"Version wu-2.4(%d) ", edit > "vers.c";\
diff -rc2 2.4-/support/makefiles/Makefile.sol 2.4+/support/makefiles/Makefile.sol
*** 2.4-/support/makefiles/Makefile.sol	Fri Apr  1 11:03:47 1994
--- 2.4+/support/makefiles/Makefile.sol	Sun Sep  3 22:42:30 1995
***************
*** 5,9 ****
  IFLAGS = 
  LFLAGS = 
! CFLAGS = -g -DDEBUG ${IFLAGS} ${LFLAGS}
  
  SRCS   = fnmatch.c strcasestr.c strsep.c authuser.c 
--- 5,9 ----
  IFLAGS = 
  LFLAGS = 
! CFLAGS = -O -DDEBUG ${IFLAGS} ${LFLAGS}
  
  SRCS   = fnmatch.c strcasestr.c strsep.c authuser.c