martin      97/11/25 13:34:13

  Modified:    src/modules/proxy proxy_ftp.c
  Log:
  Fix for the buggy behavior of proxy_ftp.c which would return incorrect links
  for ".." directory entries , depending on the fact whether the request
  contained a trailing slash or not.
  
  Also add a small "feature": the full directory path broken down into separate
  clickable path components which makes traversal of public ftp servers much
  easier.
  
  Future improvements in this area include:
  0) add appropriate cache control headers to prevent caches from keeping
     sensitive documents (user:password@)
  1) make clickable header optional ("ProxyOptions +ClickHeader"
  2) return an external redirection if proxy_ftp detects a directory but the
     request did not contain a trailing slash (that would make the current BASE
     HREF= header field obsolete which in turn would allow the removal of the
     last occurrence of the "user:password@" prefix from the generated 
document).
  3) return a 401 authenticate reply if the addressed ftp server requires a
     user name (other than "anonymous") or a password (other than "apache@"),
     unless the request contained a WWW-Authenticate: header already.
  4) Optionally convert requests ftp://user:[EMAIL PROTECTED]/ on-the-fly into
     requests of the form ftp://host/ plus the appropriate WWW-Authenticate:
     header when forwarding to an upstream proxy, lessening the danger of
     publishing passwords thru use of log file analyzers.
  
  Reviewed by:  Ken Coar, Roy T. Fielding
  
  Revision  Changes    Path
  1.42      +96 -67    apachen/src/modules/proxy/proxy_ftp.c
  
  Index: proxy_ftp.c
  ===================================================================
  RCS file: /home/cvs/apachen/src/modules/proxy/proxy_ftp.c,v
  retrieving revision 1.41
  retrieving revision 1.42
  diff -u -u -r1.41 -r1.42
  --- proxy_ftp.c       1997/10/22 20:30:07     1.41
  +++ proxy_ftp.c       1997/11/25 21:34:12     1.42
  @@ -114,11 +114,11 @@
       port = DEFAULT_FTP_PORT;
       err = proxy_canon_netloc(p, &url, &user, &password, &host, &port);
       if (err)
  -     return BAD_REQUEST;
  +     return HTTP_BAD_REQUEST;
       if (user != NULL && !ftp_check_string(user))
  -     return BAD_REQUEST;
  +     return HTTP_BAD_REQUEST;
       if (password != NULL && !ftp_check_string(password))
  -     return BAD_REQUEST;
  +     return HTTP_BAD_REQUEST;
   
   /* now parse path/parameters args, according to rfc1738 */
   /* N.B. if this isn't a true proxy request, then the URL path
  @@ -131,28 +131,28 @@
        *(strp++) = '\0';
        parms = proxy_canonenc(p, strp, strlen(strp), enc_parm, r->proxyreq);
        if (parms == NULL)
  -         return BAD_REQUEST;
  +         return HTTP_BAD_REQUEST;
       }
       else
        parms = "";
   
       path = proxy_canonenc(p, url, strlen(url), enc_path, r->proxyreq);
       if (path == NULL)
  -     return BAD_REQUEST;
  +     return HTTP_BAD_REQUEST;
       if (!ftp_check_string(path))
  -     return BAD_REQUEST;
  +     return HTTP_BAD_REQUEST;
   
       if (!r->proxyreq && r->args != NULL) {
        if (strp != NULL) {
            strp = proxy_canonenc(p, r->args, strlen(r->args), enc_parm, 1);
            if (strp == NULL)
  -             return BAD_REQUEST;
  +             return HTTP_BAD_REQUEST;
            parms = pstrcat(p, parms, "?", strp, NULL);
        }
        else {
            strp = proxy_canonenc(p, r->args, strlen(r->args), enc_fpath, 1);
            if (strp == NULL)
  -             return BAD_REQUEST;
  +             return HTTP_BAD_REQUEST;
            path = pstrcat(p, path, "?", strp, NULL);
        }
        r->args = NULL;
  @@ -180,7 +180,7 @@
    */
   static int ftp_getrc(BUFF *f)
   {
  -    int i, len, status;
  +    int len, status;
       char linebuff[100], buff[5];
   
       len = bgets(linebuff, 100, f);
  @@ -194,7 +194,7 @@
        status = 100 * linebuff[0] + 10 * linebuff[1] + linebuff[2] - 111 * '0';
   
       if (linebuff[len - 1] != '\n') {
  -     i = bskiplf(f);
  +     (void)bskiplf(f);
       }
   
   /* skip continuation lines */
  @@ -206,7 +206,7 @@
            if (len == -1)
                return -1;
            if (linebuff[len - 1] != '\n') {
  -             i = bskiplf(f);
  +             (void)bskiplf(f);
            }
        } while (memcmp(linebuff, buff, 4) != 0);
       }
  @@ -240,27 +240,91 @@
       char buf2[IOBUFSIZE];
       char *filename;
       char *tempurl;
  -    char *newurlptr;
       int searchidx = 0;
       char *searchptr = NULL;
       int firstfile = 1;
       char urlptr[HUGE_STRING_LEN];
  -    long total_bytes_sent;
  +    unsigned long total_bytes_sent = 0;
       register int n, o, w;
  +    int hostlen;
       conn_rec *con = r->connection;
  +    char *dir, *path, *reldir, *site, *psite;
   
       tempurl = pstrdup(r->pool, url);
  -    if ((n = strcspn(tempurl, "@")) != strlen(tempurl)) {    /* hide 
user/passwd */
  +
  +    (void)decodeenc(tempurl);
  +
  +    /* Determine length of "scheme://site" prefix */
  +    for (hostlen=0; tempurl[hostlen]!='/'; ++hostlen)
  +     continue;
  +    if (tempurl[hostlen] == '/' && tempurl[hostlen+1] == '/') {
  +     for (hostlen+=2; tempurl[hostlen]!='/' && tempurl[hostlen]!='?'; 
++hostlen)
  +         continue;
  +    } else {
  +     hostlen = 0;
  +    }
  +
  +    /* Save "scheme://site" prefix */
  +    site = psite = pstrndup(r->pool, tempurl, hostlen);
  +
  +    if ((n = strcspn(tempurl, "@")) != strlen(tempurl) && n < hostlen) {    
/* hide user/passwd */
        memmove(tempurl + (n - 5), tempurl, 6);
        tempurl += n - 5;       /* leave room for ftp:// */
  +     hostlen -= (n-5);
  +
  +     /* Save "scheme://site" prefix without user/password */
  +     site = pstrndup(r->pool, tempurl, hostlen);
       }
   
  -    n = decodeenc(tempurl);
  -    ap_snprintf(buf, sizeof(buf), 
"<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><H1>Directory %s</H1><HR><PRE>", 
tempurl, tempurl);
  -    bwrite(con->client, buf, strlen(buf));
  +    /* Save "scheme://site" prefix */
  +    site = pstrndup(r->pool, tempurl, hostlen);
  +
  +    /* Copy path, strip (all except the last) trailing slashes */
  +    path = dir = pstrcat(r->pool, tempurl+hostlen, "/", NULL);
  +    while ((n = strlen(path)) > 1 && path[n-1] == '/' && path[n-2] == '/')
  +     path[n-1] = '\0';
  +
  +    /* print "ftp://host/"; */
  +    ap_snprintf(buf, sizeof(buf), "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 
3.2 Final//EN\">\n"
  +             "<HTML><HEAD><TITLE>%s</TITLE>\n"
  +             "<BASE HREF=\"%s%s\"></HEAD>\n"
  +             "<BODY><H2>Directory of "
  +             "<A HREF=\"/\">%s</A>/",
  +             tempurl, psite, path, site, site);
  +    bputs(buf, con->client);
       if (f2 != NULL)
  -     bwrite(f2, buf, strlen(buf));
  -    total_bytes_sent = strlen(buf);
  +     bputs(buf, f2);
  +    total_bytes_sent += strlen(buf);
  +
  +    while ((dir = strchr(dir+1, '/')) != NULL)
  +    {
  +     *dir = '\0';
  +     if ((reldir = strrchr(path+1, '/'))==NULL)
  +         reldir = path+1;
  +     else
  +         ++reldir;
  +     /* print "path/" component */
  +     ap_snprintf(buf, sizeof(buf), "<A HREF=\"/%s/\">%s</A>/", path+1, 
reldir);
  +     bputs(buf, con->client);
  +    if (f2 != NULL)
  +         bputs(buf, f2);
  +     total_bytes_sent += strlen(buf);
  +     *dir = '/';
  +    }
  +    ap_snprintf(buf, sizeof(buf), "</H2>\n<HR><PRE>");
  +    bputs(buf, con->client);
  +    if (f2 != NULL)
  +         bputs(buf, f2);
  +    total_bytes_sent += strlen(buf);
  +
  +    for (hostlen=0; url[hostlen]!='/'; ++hostlen)
  +     continue;
  +    if (url[hostlen] == '/' && url[hostlen+1] == '/') {
  +     for (hostlen+=2; url[hostlen]!='/' && url[hostlen]!='?'; ++hostlen)
  +         continue;
  +    } else
  +     hostlen = 0;
  +
       while (!con->aborted) {
        n = bgets(buf, IOBUFSIZE, f);
        if (n == -1) {          /* input error */
  @@ -270,18 +334,18 @@
        }
        if (n == 0)
            break;              /* EOF */
  -     if (buf[0] == 'l') {
  -         char *link_ptr;
  +     if (buf[0] == 'l' && (filename=strstr(buf, " -> ")) != NULL) {
  +         char *link_ptr = filename;
   
  -         link_ptr = strstr(buf, " -> ");
  -         filename = link_ptr;
            do
                filename--;
            while (filename[0] != ' ');
            *(filename++) = 0;
            *(link_ptr++) = 0;
  -         ap_snprintf(urlptr, sizeof(urlptr), "%s%s%s", url, (url[strlen(url) 
- 1] == '/' ? "" : "/"), filename);
  -         ap_snprintf(buf2, sizeof(urlptr), "%s <A HREF=\"%s\">%s 
%s</A>\015\012", buf, urlptr, filename, link_ptr);
  +         if ((n = strlen(link_ptr)) > 1 && link_ptr[n - 1] == '\n')
  +           link_ptr[n - 1] = '\0';
  +         ap_snprintf(urlptr, sizeof(urlptr), "%s%s%s", url+hostlen, 
(url[strlen(url) - 1] == '/' ? "" : "/"), filename);
  +         ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s %s</A>\n", 
buf, filename, filename, link_ptr);
            strncpy(buf, buf2, sizeof(buf) - 1);
            buf[sizeof(buf) - 1] = '\0';
            n = strlen(buf);
  @@ -312,48 +376,12 @@
            }
   
            /* Special handling for '.' and '..' */
  -         if (!strcmp(filename, ".")) {
  -             ap_snprintf(urlptr, sizeof(urlptr), "%s", url);
  -             ap_snprintf(buf2, sizeof(buf2), "%s <A 
HREF=\"%s\">%s</A>\015\012", buf, urlptr, filename);
  -         }
  -         else if (!strcmp(filename, "..")) {
  -             char temp[200];
  -             char newpath[200];
  -             char *method, *host, *path, *newfile;
  -
  -             strncpy(temp, url, sizeof(temp) - 1);
  -             temp[sizeof(temp) - 1] = '\0';
  -             method = temp;
  -
  -             host = strchr(method, ':');
  -             if (host == NULL)
  -                 host = "";
  -             else
  -                 *(host++) = 0;
  -             host++;
  -             host++;
  -
  -             path = strchr(host, '/');
  -             if (path == NULL)
  -                 path = "";
  -             else
  -                 *(path++) = 0;
  -
  -             strncpy(newpath, path, sizeof(newpath) - 1);
  -             newpath[sizeof(newpath) - 1] = '\0';
  -             newfile = strrchr(newpath, '/');
  -             if (newfile)
  -                 *(newfile) = 0;
  -             else
  -                 newpath[0] = 0;
  -
  -             ap_snprintf(urlptr, sizeof(urlptr), "%s://%s/%s", method, host, 
newpath);
  -             ap_snprintf(buf2, sizeof(buf2), "%s <A 
HREF=\"%s\">%s</A>\015\012", buf, urlptr, filename);
  +         if (!strcmp(filename, ".") || !strcmp(filename, "..") || buf[0] == 
'd') {
  +             ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s/\">%s</A>\n",
  +                 buf, filename, filename);
            }
            else {
  -             ap_snprintf(urlptr, sizeof(urlptr), "%s%s%s", url, 
(url[strlen(url) - 1] == '/' ? "" : "/"), filename);
  -             newurlptr = encode_space(r, urlptr);
  -             ap_snprintf(buf2, sizeof(buf2), "%s <A 
HREF=\"%s\">%s</A>\015\012", buf, newurlptr, filename);
  +             ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s</A>\n", 
buf, filename, filename);
            }
            strncpy(buf, buf2, sizeof(buf));
            buf[sizeof(buf) - 1] = '\0';
  @@ -376,9 +404,10 @@
            o += w;
        }
       }
  -    bputs("</PRE><HR></BODY></HTML>\015\012", con->client);
  +    strcpy (buf, "</PRE><HR></BODY></HTML>\n");
  +    bputs(buf, con->client);
       if (f2 != NULL)
  -     bputs("</PRE><HR></BODY></HTML>\015\012", f2);
  +     bputs(buf, f2);
       total_bytes_sent += strlen(buf);
       bflush(con->client);
   
  
  
  

Reply via email to