COMMAND

    wu-ftpd

SYSTEMS AFFECTED

    Systems running wu-ftpd beta 13

PROBLEM

    Note that many sites may not be vulnerable to this bug.  It  works
    only if  you had  added the  /./ to  the end  of the anonymous ftp
    path in  /etc/passwd while  rearranging the  ftp user.   The  code
    does not expect /./ at the end of the anonymous ftp path and  does
    not behave correctly if it exists.

    There is a potentially serious  bug in ftpd.c in wu-ftpd  beta 13.
    During anonymous  login, the  /./ is  not clipped  off the  struct
    passwd pw->pw_dir field that is  saved as the chroot directory  in
    ftpd.c.

    Because  the  /./  is  still  on  the end of the pw->pw_dir field,
    upl_check()   'upload'   directive   processing   will   fail   in
    extensions.c because the file name paths will not compare.  It  is
    highly unlikely  that the  upload directive  root path  would also
    have the /./ on the end.

    If  upload  directive  processing  fails  for  the anonymous user,
    sites that depend  on upload directives  to properly set  incoming
    file permissions could find their site security compromised.

    For example, it is fairly common  to set incoming files to not  be
    readable to  the anonymous  user; this  prevents files  from being
    traded through  an anonymous  site without  the permission  of the
    owner.   With  this  bug,  all  uploaded  files  are  owned by the
    anonymous user, with default permissions set by CMASK.

    Credit goes to Michael Brennen.

SOLUTION

    The patch below is Michael's version of a fix (another one!).

    --- ftpd.c.orig Wed May 21 09:29:17 1997
    +++ ftpd.c      Fri Jun 20 11:19:01 1997
    @@ -1550,6 +1550,8 @@
         expand_id();

         if (anonymous || guest) {
    +        char *sp;
    +
             /* We MUST do a chdir() after the chroot. Otherwise the old current
              * directory will be accessible as "." outside the new root! */
     #ifdef VIRTUAL
    @@ -1559,28 +1561,19 @@
                 pw->pw_dir = sgetsave(virtual_root);
             }
     #endif
    -        if (anonymous) {
    +        /* determine root and home directory */
    +
    +        if ((sp = strstr(pw->pw_dir, "/./")) == NULL) {
                 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
                     reply(550, "Can't set guest privileges.");
                     goto bad;
                 }
    -        } else if (guest) {
    -            char *sp;
    -
    -            /* determine root and home directory */
    +        } else {
    +            *sp++ = '\0';

    -            if ((sp = strstr(pw->pw_dir, "/./")) == NULL) {
    -                if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
    -                    reply(550, "Can't set guest privileges.");
    -                    goto bad;
    -                }
    -            } else {
    -                *sp++ = '\0';
    -
    -                if (chroot(pw->pw_dir) < 0 || chdir(++sp) < 0) {
    -                    reply(550, "Can't set guest privileges.");
    -                    goto bad;
    -                }
    +            if (chroot(pw->pw_dir) < 0 || chdir(++sp) < 0) {
    +                reply(550, "Can't set guest privileges.");
    +                goto bad;
                 }
             }
         }