Subject: Re: An extension to provide enhanced file transfer logging facilities.

From: Brian Lane <[email-masked]>
Date: Mon, 4 Sep 1995 13:24:46 -0500

Thanks A LOT for the .xferlog patch that is really nice..  I just got ftpd
for Solaris yesterday and
I have it running and everything, it works great except that the ftpwho
command doesnt seem to work
the way it should.. it doesnt show the user name and what they are doing..
in the pathnames.h file when it asks for utmp and wtmp and lastlog..  what
should i use?  /etc/utmp  and /etc/wtmp or the /etc/utmpx  wtmpx files?
what kind of permission should these files have?  /etc/utmp is a sym link to
/var/adm/utmp, same with wtmp, etc..   ftpd works great except for the
ftpwho command.. also is there a FAQ available somewhere?

Brian

---

From: "Ronald F. Guilmette" <[email-masked]>
Date: Mon, 04 Sep 1995 12:31:48 -0700

There was a small error in the patches that I posted to this mailing list
last night, i.e. the patches to implement the enhanced file-transfer logging
facility.

It appears that I forgot to close each .xferlog file after I was done
writing to it.  The net effect of this omission is/was that the ftpd
daemon could run out of file descriptors if someone did a whole lot
of file transfers during any one FTP session.

The fix was simple, and is as follows:

*** 2.4/src/ftpd.c	Sun Sep  3 22:40:22 1995
--- 2.4/src/ftpd.c	Mon Sep  4 11:43:19 1995
***************
*** 1401,1407 ****
  		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));
--- 1401,1408 ----
  		continue;
  	    }
! 	    if ((xferlog = open(buf, O_WRONLY | O_APPEND)) != -1) {
  		log_xfer(xferlog,start_time,name,options,xfer_type,logname);
! 		close(xferlog);
! 	    } else if (errno != ENOENT)
  		syslog(LOG_ERR, "Error opening logging file %s: %s",
  			buf, strerror (errno));

I am including below a complete revised version of the ``enhanced logging''
patches which include the above change.  I have also put up a copy of the
revised patches for anonymous FTP in the ftp.ccnet.com:~ftp/users/rfg/wu-ftpd
directory, along with pre-patched source tarfile distributions (both gzipped
and compressed) in the same directory.

Ron Guilmette
Infinite Monkeys & Co.

cut here for complete patch kit... use `patch -p1' to apply these.
-----------------------------------------------------------------------------
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	Mon Sep  4 11:43:19 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,1416 ----
  }
  
+ 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);
+ 		close(xferlog);
+ 	    } 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;
--- 1588,1595 ----
  
    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.
--- 1668,1672 ----
          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;
--- 1752,1758 ----
  
    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 *);
--- 2431,2435 ----
      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);
--- 2438,2446 ----
  #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