Squid-2.2.STABLE4: FTP password URLs Changes Squid to preserve any password which was entered in the URL when BASE HREF is used to "correct" directory URLs without a trailing /. This patch also fixes a minor issue with URL encoding of filenames. Squid only encoded those characters classified as "unsafe", not those classified as "reserved". What this means is for example if a directory contains a file with a name including "/", ";" or other reserved characters then Squid (or actually the browser, but Squid gets the blaim) would be confused. Index: squid/include/util.h diff -u squid/include/util.h:1.1.1.13 squid/include/util.h:1.1.1.13.22.1 --- squid/include/util.h:1.1.1.13 Sun Feb 14 23:29:40 1999 +++ squid/include/util.h Tue Jul 13 00:46:42 1999 @@ -80,6 +80,7 @@ /* rfc1738.c */ extern char *rfc1738_escape(const char *); +extern char *rfc1738_escape_part(const char *); extern void rfc1738_unescape(char *); #if XMALLOC_STATISTICS Index: squid/lib/rfc1738.c diff -u squid/lib/rfc1738.c:1.1.1.9 squid/lib/rfc1738.c:1.1.1.9.2.1 --- squid/lib/rfc1738.c:1.1.1.9 Tue Jul 13 00:09:15 1999 +++ squid/lib/rfc1738.c Tue Jul 13 00:46:49 1999 @@ -68,12 +68,23 @@ (char) 0x20 /* space */ }; +static char rfc1738_reserved_chars[] = +{ + (char) 0x3b, /* ; */ + (char) 0x2f, /* / */ + (char) 0x3f, /* ? */ + (char) 0x3a, /* : */ + (char) 0x40, /* @ */ + (char) 0x3d, /* = */ + (char) 0x26 /* & */ +}; + /* * rfc1738_escape - Returns a static buffer contains the RFC 1738 * compliant, escaped version of the given url. */ -char * -rfc1738_escape(const char *url) +static char * +rfc1738_do_escape(const char *url, int encode_reserved) { static char *buf; static size_t bufsize = 0; @@ -96,6 +107,13 @@ break; } } + /* RFC 1738 defines these chars as reserved */ + for (i = 0; i < sizeof(rfc1738_reserved_chars) && encode_reserved ; i++) { + if (*p == rfc1738_reserved_chars[i]) { + do_escape = 1; + break; + } + } /* RFC 1738 says any control chars (0x00-0x1F) are encoded */ if ((unsigned char) *p <= (unsigned char) 0x1F) { do_escape = 1; @@ -122,6 +140,26 @@ } *q = '\0'; return (buf); +} + +/* + * rfc1738_escape - Returns a static buffer contains the RFC 1738 + * compliant, escaped version of the given url. + */ +char * +rfc1738_escape(const char *url) +{ + return rfc1738_do_escape(url, 0); +} + +/* + * rfc1738_escape_part - Returns a static buffer contains the RFC 1738 + * compliant, escaped version of the given url segment. + */ +char * +rfc1738_escape_part(const char *url) +{ + return rfc1738_do_escape(url, 1); } /* Index: squid/src/ftp.c diff -u squid/src/ftp.c:1.1.1.35.2.3 squid/src/ftp.c:1.1.1.35.2.5 --- squid/src/ftp.c:1.1.1.35.2.3 Tue Jul 13 00:24:51 1999 +++ squid/src/ftp.c Tue Jul 13 00:47:52 1999 @@ -89,6 +89,7 @@ char *reply_hdr; int reply_hdr_state; char *title_url; + char *base_href; int conn_att; int login_att; ftp_state_t state; @@ -297,6 +298,7 @@ safe_free(ftpState->old_reply); safe_free(ftpState->old_filepath); safe_free(ftpState->title_url); + safe_free(ftpState->base_href); safe_free(ftpState->filepath); safe_free(ftpState->data.host); if (ftpState->data.fd > -1) { @@ -356,7 +358,7 @@ storeAppendPrintf(e, "\n"); if (ftpState->flags.use_base) storeAppendPrintf(e, "\n", - ftpState->title_url); + ftpState->base_href); storeAppendPrintf(e, "\n"); if (ftpState->cwd_message) { storeAppendPrintf(e, "
\n");
@@ -692,7 +694,7 @@
 	}
     }
     /* {icon} {text} . . . {date}{size}{chdir}{view}{download}{link}\n  */
-    xstrncpy(href, rfc1738_escape(parts->name), 2048);
+    xstrncpy(href, rfc1738_escape_part(parts->name), 2048);
     xstrncpy(text, parts->showname, 2048);
     switch (parts->type) {
     case 'd':
@@ -991,6 +993,21 @@
     if (request->port != urlDefaultPort(PROTO_FTP))
 	snprintf(&t[strlen(t)], len - strlen(t), ":%d", request->port);
     strcat(t, strBuf(request->urlpath));
+    t = ftpState->base_href = xcalloc(len, 1);
+    strcat(t, "ftp://");
+    if (strcmp(ftpState->user, "anonymous")) {
+	strcat(t, rfc1738_escape_part(ftpState->user));
+	if (ftpState->password_url) {
+	    strcat(t, ":");
+	    strcat(t, rfc1738_escape_part(ftpState->password));
+	}
+	strcat(t, "@");
+    }
+    strcat(t, request->host);
+    if (request->port != urlDefaultPort(PROTO_FTP))
+	snprintf(&t[strlen(t)], len - strlen(t), ":%d", request->port);
+    strcat(t, strBuf(request->urlpath));
+    strcat(t, "/");
 }
 
 void
Index: squid/src/gopher.c
diff -u squid/src/gopher.c:1.1.1.20 squid/src/gopher.c:1.1.1.20.22.1
--- squid/src/gopher.c:1.1.1.20	Sun Feb 14 23:30:00 1999
+++ squid/src/gopher.c	Tue Jul 13 00:46:49 1999
@@ -430,7 +430,7 @@
 				port[0] = 0;	/* 0 means none */
 			}
 			/* escape a selector here */
-			escaped_selector = xstrdup(rfc1738_escape(selector));
+			escaped_selector = xstrdup(rfc1738_escape_part(selector));
 
 			switch (gtype) {
 			case GOPHER_DIRECTORY: