]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Cross-site scripting fixes by Robert Collins and Henrik Nordstrom
authorhno <>
Sun, 5 Nov 2000 06:04:09 +0000 (06:04 +0000)
committerhno <>
Sun, 5 Nov 2000 06:04:09 +0000 (06:04 +0000)
Everywhere where Squid inserts text received from the network into
a HTML page (error pages, FTP listings, Gopher listings, ...) care
must be taken to ensure that the text is properly encoded as HTML,
or a malicious user might be able to insert script code or other
HTML tags, and exploit the web browser of any user visiting their
page or clicking on that funny link received in a email..

include/util.h
lib/Makefile.in
src/errorpage.cc
src/ftp.cc
src/gopher.cc

index 232b70b7dc6762081928958315ed2a3cba632ebe..8e2bfebd2f87219b2e828d2d2e31da3cf54f2aca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: util.h,v 1.55 2000/10/17 08:06:01 adrian Exp $
+ * $Id: util.h,v 1.56 2000/11/04 23:04:09 hno Exp $
  *
  * AUTHOR: Harvest Derived
  *
@@ -84,6 +84,9 @@ extern char *rfc1738_escape_unescaped(const char *);
 extern char *rfc1738_escape_part(const char *);
 extern void rfc1738_unescape(char *);
 
+/* html.c */
+extern char *html_quote(const char *);
+
 #if XMALLOC_STATISTICS
 extern void malloc_statistics(void (*)(int, int, int, void *), void *);
 #endif
index df1d6bb5d69e01a58b49bc61dfdc109442193d88..10c16865607042b38fea820b4f7e10a1c9c45c6b 100644 (file)
@@ -1,5 +1,5 @@
 #
-#  $Id: Makefile.in,v 1.45 1999/07/13 14:51:03 wessels Exp $
+#  $Id: Makefile.in,v 1.46 2000/11/04 23:04:09 hno Exp $
 #
 prefix         = @prefix@
 top_srcdir     = @top_srcdir@
@@ -39,6 +39,7 @@ UTILOBJS      = rfc1123.o \
                  Stack.o \
                  hash.o \
                  heap.o \
+                  html.o \
                  $(LIBOBJS)
 REGEXOBJS      = GNUregex.o
 DLMALLOCOBJS   = dlmalloc.o
index 33685197d26bb8c631d2aef13f3564679b4602ec..a0b8be61ce0cc37de993a1f8a685fc281aa3faa6 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: errorpage.cc,v 1.154 2000/07/18 06:16:41 wessels Exp $
+ * $Id: errorpage.cc,v 1.155 2000/11/04 23:04:10 hno Exp $
  *
  * DEBUG: section 4     Error Generation
  * AUTHOR: Duane Wessels
@@ -423,6 +423,7 @@ errorConvert(char token, ErrorState * err)
     request_t *r = err->request;
     static MemBuf mb = MemBufNULL;
     const char *p = NULL;      /* takes priority over mb if set */
+    int do_quote = 1;
 
     memBufReset(&mb);
     switch (token) {
@@ -524,6 +525,7 @@ errorConvert(char token, ErrorState * err)
            memBufPrintf(&mb, "%s", sign_mb.buf);
            memBufClean(&sign_mb);
            err->page_id = saved_id;
+           do_quote = 0;
        } else {
            /* wow, somebody put %S into ERR_SIGNATURE, stop recursion */
            p = "[%S]";
@@ -561,6 +563,8 @@ errorConvert(char token, ErrorState * err)
        p = mb.buf;             /* do not use mb after this assignment! */
     assert(p);
     debug(4, 3) ("errorConvert: %%%c --> '%s'\n", token, p);
+    if (do_quote)
+       p = html_quote(p);
     return p;
 }
 
index e5c69f3cc97ee542f7a644aa406ea2141c5a1e2c..a1a2f0538a52233e7443ecb277b8d700d4a886d7 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ftp.cc,v 1.296 2000/06/27 22:06:01 hno Exp $
+ * $Id: ftp.cc,v 1.297 2000/11/04 23:04:10 hno Exp $
  *
  * DEBUG: section 9     File Transfer Protocol (FTP)
  * AUTHOR: Harvest Derived
@@ -354,22 +354,23 @@ ftpListingStart(FtpStateData * ftpState)
     wordlist *w;
     char *dirup;
     int i, j, k;
+    char *title;
     storeBuffer(e);
     storeAppendPrintf(e, "<!-- HTML listing generated by Squid %s -->\n",
        version_string);
     storeAppendPrintf(e, "<!-- %s -->\n", mkrfc1123(squid_curtime));
     storeAppendPrintf(e, "<HTML><HEAD><TITLE>\n");
     storeAppendPrintf(e, "FTP Directory: %s\n",
-       ftpState->title_url);
+       html_quote(ftpState->title_url));
     storeAppendPrintf(e, "</TITLE>\n");
     if (ftpState->flags.use_base)
        storeAppendPrintf(e, "<BASE HREF=\"%s\">\n",
-           ftpState->base_href);
+           html_quote(ftpState->base_href));
     storeAppendPrintf(e, "</HEAD><BODY>\n");
     if (ftpState->cwd_message) {
        storeAppendPrintf(e, "<PRE>\n");
        for (w = ftpState->cwd_message; w; w = w->next)
-           storeAppendPrintf(e, "%s\n", w->key);
+           storeAppendPrintf(e, "%s\n", html_quote(w->key));
        storeAppendPrintf(e, "</PRE>\n");
        storeAppendPrintf(e, "<HR>\n");
        wordlistDestroy(&ftpState->cwd_message);
@@ -378,25 +379,26 @@ ftpListingStart(FtpStateData * ftpState)
     storeAppendPrintf(e, "FTP Directory: ");
     /* "ftp://" == 6 characters */
     assert(strlen(ftpState->title_url) >= 6);
-    for (i = 6, j = 0; ftpState->title_url[i]; j = i) {
+    title = html_quote(ftpState->title_url);
+    for (i = 6, j = 0; title[i]; j = i) {
        storeAppendPrintf(e, "<A HREF=\"");
-       i += strcspn(&ftpState->title_url[i], "/");
-       if (ftpState->title_url[i] == '/')
+       i += strcspn(&title[i], "/");
+       if (title[i] == '/')
            i++;
        for (k = 0; k < i; k++)
-           storeAppendPrintf(e, "%c", ftpState->title_url[k]);
+           storeAppendPrintf(e, "%c", title[k]);
        storeAppendPrintf(e, "\">");
        for (k = j; k < i - 1; k++)
-           storeAppendPrintf(e, "%c", ftpState->title_url[k]);
+           storeAppendPrintf(e, "%c", title[k]);
        if (ftpState->title_url[k] != '/')
-           storeAppendPrintf(e, "%c", ftpState->title_url[k++]);
+           storeAppendPrintf(e, "%c", title[k++]);
        storeAppendPrintf(e, "</A>");
        if (k < i)
-           storeAppendPrintf(e, "%c", ftpState->title_url[k++]);
+           storeAppendPrintf(e, "%c", title[k++]);
        if (i == j) {
            /* Error guard, or "assert" */
            storeAppendPrintf(e, "ERROR: Failed to parse URL: %s\n",
-               ftpState->title_url);
+               html_quote(ftpState->title_url));
            debug(9, 0) ("Failed to parse URL: %s\n", ftpState->title_url);
            break;
        }
@@ -648,7 +650,7 @@ ftpHtmlifyListEntry(char *line, FtpStateData * ftpState)
        return html;
     }
     /* Handle builtin <dirup> */
-    if (!strcmp(line, "<internal-dirup>")) {
+    if (strcmp(line, "<internal-dirup>") == 0) {
        /* <A HREF="{href}">{icon}</A> <A HREF="{href}">{text}</A> {link} */
        snprintf(icon, 2048, "<IMG BORDER=0 SRC=\"%s\" ALT=\"%-6s\">",
            mimeGetIconURL("internal-dirup"),
@@ -717,10 +719,13 @@ ftpHtmlifyListEntry(char *line, FtpStateData * ftpState)
            mimeGetIconURL("internal-link"),
            "[LINK]");
        /* sometimes there is an 'l' flag, but no "->" link */
-       if (parts->link)
+       if (parts->link) {
+           char *link2 = xstrdup(html_quote(rfc1738_escape(parts->link)));
            snprintf(link, 2048, " -> <A HREF=\"%s\">%s</A>",
-               rfc1738_escape(parts->link),
-               parts->link);
+               link2,
+               html_quote(parts->link));
+           safe_free(link2);
+       }
        break;
     case '\0':
        snprintf(icon, 2048, "<IMG BORDER=0 SRC=\"%s\" ALT=\"%-6s\">",
@@ -728,7 +733,7 @@ ftpHtmlifyListEntry(char *line, FtpStateData * ftpState)
            "[UNKNOWN]");
        snprintf(chdir, 2048, " <A HREF=\"%s/;type=d\"><IMG BORDER=0 SRC=\"%s\" "
            "ALT=\"[DIR]\"></A>",
-           rfc1738_escape(parts->name),
+           rfc1738_escape_part(parts->name),
            mimeGetIconURL("internal-dir"));
        break;
     case '-':
@@ -755,13 +760,13 @@ ftpHtmlifyListEntry(char *line, FtpStateData * ftpState)
     if (parts->type != '\0') {
        snprintf(html, 8192, "<A HREF=\"%s\">%s</A> <A HREF=\"%s\">%s</A>%s "
            "%s%8s%s%s%s%s\n",
-           href, icon, href, text, dots_fill(strlen(text)),
+           href, icon, href, html_quote(text), dots_fill(strlen(text)),
            parts->date, size, chdir, view, download, link);
     } else {
        /* Plain listing. {icon} {text} ... {chdir}{view}{download} */
        snprintf(html, 8192, "<A HREF=\"%s\">%s</A> <A HREF=\"%s\">%s</A>%s "
            "%s%s%s%s\n",
-           href, icon, href, text, dots_fill(strlen(text)),
+           href, icon, href, html_quote(text), dots_fill(strlen(text)),
            chdir, view, download, link);
     }
     ftpListPartsFree(&parts);
index 1c7f03a78e0094809cbbf1a8f2249f6bc81b3de9..d20b144bffa97476d0f54e101fb3090ff1024568 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: gopher.cc,v 1.155 2000/06/27 22:06:02 hno Exp $
+ * $Id: gopher.cc,v 1.156 2000/11/04 23:04:10 hno Exp $
  *
  * DEBUG: section 10    Gopher
  * AUTHOR: Harvest Derived
@@ -469,19 +469,20 @@ gopherToHTML(GopherStateData * gopherState, char *inbuf, int len)
                            break;
                        }
 
-
                        memset(tmpbuf, '\0', TEMP_BUF_SIZE);
                        if ((gtype == GOPHER_TELNET) || (gtype == GOPHER_3270)) {
                            if (strlen(escaped_selector) != 0)
-                               snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG BORDER=0 SRC=\"%s\"> <A HREF=\"telnet://%s@%s/\">%s</A>\n",
-                                   icon_url, escaped_selector, host, name);
+                               snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG BORDER=0 SRC=\"%s\"> <A HREF=\"telnet://%s@%s%s%s/\">%s</A>\n",
+                                   icon_url, escaped_selector, rfc1738_escape_part(host), 
+                                   *port ? ":" : "", port, html_quote(name));
                            else
-                               snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG BORDER=0 SRC=\"%s\"> <A HREF=\"telnet://%s/\">%s</A>\n",
-                                   icon_url, host, name);
+                               snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG BORDER=0 SRC=\"%s\"> <A HREF=\"telnet://%s%s%s/\">%s</A>\n",
+                                   icon_url, rfc1738_escape_part(host), *port ? ":" : "",
+                                   port, html_quote(name));
 
                        } else {
                            snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG BORDER=0 SRC=\"%s\"> <A HREF=\"gopher://%s/%c%s\">%s</A>\n",
-                               icon_url, host, gtype, escaped_selector, name);
+                               icon_url, host, gtype, escaped_selector, html_quote(name));
                        }
                        safe_free(escaped_selector);
                        strcat(outbuf, tmpbuf);
@@ -515,10 +516,10 @@ gopherToHTML(GopherStateData * gopherState, char *inbuf, int len)
                        break;
 
                    if (gopherState->cso_recno != recno) {
-                       snprintf(tmpbuf, TEMP_BUF_SIZE, "</PRE><HR><H2>Record# %d<br><i>%s</i></H2>\n<PRE>", recno, result);
+                       snprintf(tmpbuf, TEMP_BUF_SIZE, "</PRE><HR><H2>Record# %d<br><i>%s</i></H2>\n<PRE>", recno, html_quote(result));
                        gopherState->cso_recno = recno;
                    } else {
-                       snprintf(tmpbuf, TEMP_BUF_SIZE, "%s\n", result);
+                       snprintf(tmpbuf, TEMP_BUF_SIZE, "%s\n", html_quote(result));
                    }
                    strcat(outbuf, tmpbuf);
                    gopherState->data_in = 1;
@@ -543,7 +544,7 @@ gopherToHTML(GopherStateData * gopherState, char *inbuf, int len)
                    case 502:   /* Too Many Matches */
                        {
                            /* Print the message the server returns */
-                           snprintf(tmpbuf, TEMP_BUF_SIZE, "</PRE><HR><H2>%s</H2>\n<PRE>", result);
+                           snprintf(tmpbuf, TEMP_BUF_SIZE, "</PRE><HR><H2>%s</H2>\n<PRE>", html_quote(result));
                            strcat(outbuf, tmpbuf);
                            gopherState->data_in = 1;
                            break;