Subject: Two patches/bug fixes for wu-ftpd-2.4

From: Alan Judge <[email-masked]>
Date: Sat, 25 Feb 1995 16:25:41 +0000

I've attached two patches to wu-ftpd-2.4.  Both address bugs (or what
you might choose to call bugs) in the current implementation.

The first two chunks patch the UPLOAD code to address a problem that
we hit.  If you use upload to change the ownership and protect
uploaded files _and_ your ftp area happens to be NFSed into the ftp
server (as happened to be the case here due to a server move), then
uploads won't work at all.  The problem is that the current code holds
an open file descriptor to the file to be written and then changes the
permissions on the file before writing the actual data.  This is fine
for local files, but NFS checks the permissions on every access and
will bomb out if user ftp can no longer write the file.  The patch
below moves the ownership change to after the reception of the file.
However, this introduces another problem in that other ftp users can
access and potentially download the new file during the period that it
is being written.  This is acceptable to us, but may not be to you.
A better fix would need more wide ranging changes and possibly running
part of the file reception code as root;  this may not be better :-)

The second fix addresses a clearer problem that was hitting us a lot.
We have a fairly busy server and we seemed to be building up ftp
processes that weren't going away.  Some digging with sps, lsof, and
gdb revealed that they were wedging in an accept() call in ftpd which
had no timeout arrangement.

I suspect that problem is most commonly triggered by people who are
using passive ftp clients and misconfigured firewalls so that their
connection wasn't making it.  I added a timeout so that ftpd goes away
if the incoming connection doesn't arrive in swaitmax seconds
(defaults to 90 seconds).

We still have some problems with ftpds hanging around, but they seem
to be in different states.  At least some hang around with their tcp
connections in CLOSE_WAIT, which may well be some sort of OS bug
(SunOS 4.1.3_U1).  Ideas welcome?

BTW, is there any central source of patches/updates to 2.4?
--
Alan

*** 1.1	1995/02/10 16:46:10
--- ftpd.c	1995/02/25 16:05:20
***************
*** 1529,1546 ****
          perror_reply(553, name);
          return;
      }
-     /* if we have a uid and gid, then use them. */
- 
-     if (valid > 0) {
-         oldid = geteuid();
-         (void) seteuid((uid_t) 0);
-         if ((fchown(fdout, uid, gid)) < 0) {
-             (void) seteuid(oldid);
-             perror_reply(550, "fchown");
-             return;
-         }
-         (void) seteuid(oldid);
-     }
  #endif /* UPLOAD */
  
      if (restart_point)
--- 1529,1534 ----
***************
*** 1629,1634 ****
--- 1617,1644 ----
      data = -1;
      pdata = -1;
    done:
+ #ifdef UPLOAD
+     /*
+      * if we have a uid and gid, then use them.
+      * Waiting until all the data is here opens a window where someone
+      * could read the file.
+      * However, if your ftp archive area happens to be in NFS, you don't
+      * have any choice.  It you change the ownership before writing the file,
+      * NFS will refuse to do the writes.  AJ
+      */
+ 
+     fflush(fout);
+     if (valid > 0) {
+         oldid = geteuid();
+         (void) seteuid((uid_t) 0);
+         if ((fchown(fdout, uid, gid)) < 0) {
+             (void) seteuid(oldid);
+             perror_reply(550, "fchown");
+             return;
+         }
+         (void) seteuid(oldid);
+     }
+ #endif
      (*closefunc) (fout);
  }
  
***************
*** 1707,1713 ****
--- 1717,1732 ----
          int s,
            fromlen = sizeof(from);
  
+ 	/*
+ 	 * If the far end dies or doesn't make a connection, we get stuck
+ 	 * in the accept.  Instead, cause a timeout if we don't get a
+ 	 * connect.  Use swaitmax (default 90 seconds) as a suitable
+ 	 * timeout. AJ
+ 	 */
+ 	(void) alarm((unsigned) swaitmax);
          s = accept(pdata, (struct sockaddr *) &from, &fromlen);
+ 	(void) alarm(0);
+ 
          if (s < 0) {
              reply(425, "Can't open data connection.");
              (void) close(pdata);