Index: squid/src/ftp.c diff -c squid/src/ftp.c:1.298.2.7 squid/src/ftp.c:1.298.2.8 *** squid/src/ftp.c:1.298.2.7 Sun Jun 23 14:10:16 2002 --- squid/src/ftp.c Sun Jun 23 14:18:58 2002 *************** *** 461,471 **** #define MAX_TOKENS 64 - #define SCAN_FTP1 "%[0123456789]" - #define SCAN_FTP2 "%[0123456789:]" - #define SCAN_FTP3 "%[0123456789]-%[0123456789]-%[0123456789]" - #define SCAN_FTP4 "%[0123456789]:%[0123456789]%[AaPp]%[Mm]" - static ftpListParts * ftpListParseParts(const char *buf, struct _ftp_flags flags) { --- 461,466 ---- *************** *** 475,490 **** char *tokens[MAX_TOKENS]; int i; int n_tokens; ! static char sbuf[128]; char *xbuf = NULL; if (buf == NULL) return NULL; if (*buf == '\0') return NULL; p = xcalloc(1, sizeof(ftpListParts)); n_tokens = 0; ! for (i = 0; i < MAX_TOKENS; i++) ! tokens[i] = (char *) NULL; xbuf = xstrdup(buf); if (flags.tried_nlst) { /* Machine readable format, one name per line */ --- 470,497 ---- char *tokens[MAX_TOKENS]; int i; int n_tokens; ! static char tbuf[128]; char *xbuf = NULL; + static int scan_ftp_initialized = 0; + static regex_t scan_ftp_integer; + static regex_t scan_ftp_time; + static regex_t scan_ftp_dostime; + static regex_t scan_ftp_dosdate; + + if (!scan_ftp_initialized) { + scan_ftp_initialized = 1; + regcomp(&scan_ftp_integer, "^[0123456789]+$", REG_EXTENDED | REG_NOSUB); + regcomp(&scan_ftp_time, "^[0123456789:]+$", REG_EXTENDED | REG_NOSUB); + regcomp(&scan_ftp_dosdate, "^[0123456789]+-[0123456789]+-[0123456789]+$", REG_EXTENDED | REG_NOSUB); + regcomp(&scan_ftp_dostime, "^[0123456789]+:[0123456789]+[AP]M$", REG_EXTENDED | REG_NOSUB | REG_ICASE); + } if (buf == NULL) return NULL; if (*buf == '\0') return NULL; p = xcalloc(1, sizeof(ftpListParts)); n_tokens = 0; ! memset(tokens, 0, sizeof(tokens)); xbuf = xstrdup(buf); if (flags.tried_nlst) { /* Machine readable format, one name per line */ *************** *** 497,551 **** xfree(xbuf); /* locate the Month field */ for (i = 3; i < n_tokens - 2; i++) { ! if (!is_month(tokens[i])) /* Month */ continue; ! if (!sscanf(tokens[i - 1], SCAN_FTP1, sbuf)) /* Size */ continue; ! if (!sscanf(tokens[i + 1], SCAN_FTP1, sbuf)) /* Day */ continue; ! if (!sscanf(tokens[i + 2], SCAN_FTP2, sbuf)) /* Yr | hh:mm */ continue; ! p->type = *tokens[0]; ! p->size = atoi(tokens[i - 1]); ! snprintf(sbuf, 128, "%s %2s %5s", ! tokens[i], tokens[i + 1], tokens[i + 2]); ! if (!strstr(buf, sbuf)) ! snprintf(sbuf, 128, "%s %2s %-5s", ! tokens[i], tokens[i + 1], tokens[i + 2]); ! if ((t = strstr(buf, sbuf))) { ! p->date = xstrdup(sbuf); if (flags.skip_whitespace) { ! t += strlen(sbuf); while (strchr(w_space, *t)) t++; } else { /* XXX assumes a single space between date and filename * suggested by: Nathan.Bailey@cc.monash.edu.au and * Mike Battersby */ ! t += strlen(sbuf) + 1; } p->name = xstrdup(t); if ((t = strstr(p->name, " -> "))) { *t = '\0'; p->link = xstrdup(t + 4); } } break; } ! /* try it as a DOS listing */ ! if (n_tokens > 3 && p->name == NULL && ! sscanf(tokens[0], SCAN_FTP3, sbuf, sbuf, sbuf) == 3 && ! /* 04-05-70 */ ! sscanf(tokens[1], SCAN_FTP4, sbuf, sbuf, sbuf, sbuf) == 4) { ! /* 09:33PM */ if (!strcasecmp(tokens[2], "")) { p->type = 'd'; } else { p->type = '-'; p->size = atoi(tokens[2]); } ! snprintf(sbuf, 128, "%s %s", tokens[0], tokens[1]); ! p->date = xstrdup(sbuf); if (p->type == 'd') { /* Directory.. name begins with first printable after */ ct = strstr(buf, tokens[2]); --- 504,561 ---- xfree(xbuf); /* locate the Month field */ for (i = 3; i < n_tokens - 2; i++) { ! char *size = tokens[i - 1]; ! char *month = tokens[i]; ! char *day = tokens[i + 1]; ! char *year = tokens[i + 2]; ! if (!is_month(month)) continue; ! if (regexec(&scan_ftp_integer, size, 0, NULL, 0) != 0) continue; ! if (regexec(&scan_ftp_integer, day, 0, NULL, 0) != 0) continue; ! if (regexec(&scan_ftp_time, day, 0, NULL, 0) != 0) /* Yr | hh:mm */ continue; ! snprintf(tbuf, 128, "%s %2s %5s", ! month, day, year); ! if (!strstr(buf, tbuf)) ! snprintf(tbuf, 128, "%s %2s %-5s", ! month, day, year); ! if ((t = strstr(buf, tbuf))) { ! p->type = *tokens[0]; ! p->size = atoi(size); ! p->date = xstrdup(tbuf); if (flags.skip_whitespace) { ! t += strlen(tbuf); while (strchr(w_space, *t)) t++; } else { /* XXX assumes a single space between date and filename * suggested by: Nathan.Bailey@cc.monash.edu.au and * Mike Battersby */ ! t += strlen(tbuf) + 1; } p->name = xstrdup(t); if ((t = strstr(p->name, " -> "))) { *t = '\0'; p->link = xstrdup(t + 4); } + goto found; } break; } ! /* try it as a DOS listing, 04-05-70 09:33PM ... */ ! if (n_tokens > 3 && ! regexec(&scan_ftp_dosdate, tokens[0], 0, NULL, 0) == 0 && ! regexec(&scan_ftp_dostime, tokens[1], 0, NULL, 0) == 0) { if (!strcasecmp(tokens[2], "")) { p->type = 'd'; } else { p->type = '-'; p->size = atoi(tokens[2]); } ! snprintf(tbuf, 128, "%s %s", tokens[0], tokens[1]); ! p->date = xstrdup(tbuf); if (p->type == 'd') { /* Directory.. name begins with first printable after */ ct = strstr(buf, tokens[2]); *************** *** 556,588 **** ct = NULL; } else { /* A file. Name begins after size, with a space in between */ ! snprintf(sbuf, 128, " %s %s", tokens[2], tokens[3]); ! ct = strstr(buf, sbuf); if (ct) { ct += strlen(tokens[2]) + 2; } } p->name = xstrdup(ct ? ct : tokens[3]); } /* Try EPLF format; carson@lehman.com */ ! if (p->name == NULL && buf[0] == '+') { ct = buf + 1; p->type = 0; while (ct && *ct) { - long lt; time_t t; switch (*ct) { case '\t': ! sscanf(ct + 1, "%[^,]", sbuf); ! p->name = xstrdup(sbuf); break; case 's': ! sscanf(ct + 1, "%d", &(p->size)); break; case 'm': ! if (1 != sscanf(ct + 1, "%ld", <)) ! break; ! t = lt; p->date = xstrdup(ctime(&t)); *(strstr(p->date, "\n")) = '\0'; break; --- 566,601 ---- ct = NULL; } else { /* A file. Name begins after size, with a space in between */ ! snprintf(tbuf, 128, " %s %s", tokens[2], tokens[3]); ! ct = strstr(buf, tbuf); if (ct) { ct += strlen(tokens[2]) + 2; } } p->name = xstrdup(ct ? ct : tokens[3]); + goto found; } /* Try EPLF format; carson@lehman.com */ ! if (buf[0] == '+') { ct = buf + 1; p->type = 0; while (ct && *ct) { time_t t; + int l = strcspn(ct + 1, ","); + char *tmp; + if (l < 1) + goto blank; switch (*ct) { case '\t': ! p->name = xstrndup(ct + 1, l + 1); break; case 's': ! p->size = atoi(ct + 1); break; case 'm': ! t = (time_t) strtol(ct + 1, &tmp, 0); ! if (*tmp || (tmp == ct + 1)) ! break; /* not a valid integer */ p->date = xstrdup(ctime(&t)); *(strstr(p->date, "\n")) = '\0'; break; *************** *** 597,602 **** --- 610,616 ---- default: break; } + blank: ct = strstr(ct, ","); if (ct) { ct++; *************** *** 605,615 **** if (p->type == 0) { p->type = '-'; } } for (i = 0; i < n_tokens; i++) xfree(tokens[i]); ! if (p->name == NULL) ! ftpListPartsFree(&p); return p; } --- 619,634 ---- if (p->type == 0) { p->type = '-'; } + if (p->name) + goto found; + else + safe_free(p->date); } + found: for (i = 0; i < n_tokens; i++) xfree(tokens[i]); ! if (!p->name) ! ftpListPartsFree(&p); /* cleanup */ return p; } *************** *** 712,718 **** snprintf(icon, 2048, "\"%-6s\"", mimeGetIconURL("internal-dir"), "[DIR]"); ! strncat(href, "/", 2048); break; case 'l': snprintf(icon, 2048, "\"%-6s\"", --- 731,737 ---- snprintf(icon, 2048, "\"%-6s\"", mimeGetIconURL("internal-dir"), "[DIR]"); ! strcat(href, "/"); /* margin is allocated above */ break; case 'l': snprintf(icon, 2048, "\"%-6s\"", *************** *** 954,964 **** ftpState->flags.authenticated = 1; orig_user = xstrdup(ftpState->user); ftpLoginParser(auth, ftpState, FTP_LOGIN_NOT_ESCAPED); ! if (!strcmp(orig_user, ftpState->user)) { xfree(orig_user); return 1; /* same username */ } ! strcpy(ftpState->user, orig_user); xfree(orig_user); return 0; /* different username */ } --- 973,983 ---- ftpState->flags.authenticated = 1; orig_user = xstrdup(ftpState->user); ftpLoginParser(auth, ftpState, FTP_LOGIN_NOT_ESCAPED); ! if (strcmp(orig_user, ftpState->user) == 0) { xfree(orig_user); return 1; /* same username */ } ! xstrncpy(ftpState->user, orig_user, sizeof(ftpState->user)); xfree(orig_user); return 0; /* different username */ } *************** *** 1720,1726 **** int n; u_short port; int fd = ftpState->data.fd; ! char *buf = ftpState->ctrl.last_reply; LOCAL_ARRAY(char, ipaddr, 1024); debug(9, 3) ("This is ftpReadPasv\n"); if (code != 227) { --- 1739,1745 ---- int n; u_short port; int fd = ftpState->data.fd; ! char *buf; LOCAL_ARRAY(char, ipaddr, 1024); debug(9, 3) ("This is ftpReadPasv\n"); if (code != 227) { *************** *** 1728,1769 **** ftpSendPort(ftpState); return; } ! if ((int) strlen(buf) > 1024) { ! debug(9, 1) ("ftpReadPasv: Avoiding potential buffer overflow\n"); ftpSendPort(ftpState); return; } ! /* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */ ! /* ANSI sez [^0-9] is undefined, it breaks on Watcom cc */ ! debug(9, 5) ("scanning: %s\n", buf); ! n = sscanf(buf, "%[^0123456789]%d,%d,%d,%d,%d,%d", ! ipaddr, &h1, &h2, &h3, &h4, &p1, &p2); ! if (n != 7 || p1 < 0 || p2 < 0 || p1 > 255 || p2 > 255) { ! debug(9, 3) ("Bad 227 reply\n"); ! debug(9, 3) ("n=%d, p1=%d, p2=%d\n", n, p1, p2); ftpSendPort(ftpState); return; } snprintf(ipaddr, 1024, "%d.%d.%d.%d", h1, h2, h3, h4); if (!safe_inet_addr(ipaddr, NULL)) { ! debug(9, 1) ("unsafe PASV address (%s) from %s\n", ipaddr, fd_table[ftpState->ctrl.fd].ipaddr); ftpSendPort(ftpState); return; } port = ((p1 << 8) + p2); if (0 == port) { ! debug(9, 1) ("ftpReadPasv: Invalid PASV reply: %s\n", buf); ftpSendPort(ftpState); return; } if (Config.Ftp.sanitycheck) { if (strcmp(fd_table[ftpState->ctrl.fd].ipaddr, ipaddr) != 0) { ! debug(9, 1) ("unsafe PASV address (%s) from %s\n", ipaddr, fd_table[ftpState->ctrl.fd].ipaddr); ftpSendPort(ftpState); return; } if (port < 1024) { ! debug(9, 1) ("unsafe PASV port (%d) from %s\n", port, fd_table[ftpState->ctrl.fd].ipaddr); ftpSendPort(ftpState); return; } --- 1747,1788 ---- ftpSendPort(ftpState); return; } ! /* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */ ! /* ANSI sez [^0-9] is undefined, it breaks on Watcom cc */ ! debug(9, 5) ("scanning: %s\n", ftpState->ctrl.last_reply); ! buf = strstr(ftpState->ctrl.last_reply, "("); ! if (!buf) { ! debug(9, 1) ("Unsafe PASV reply from %s: '%s'\n", fd_table[ftpState->ctrl.fd].ipaddr, ftpState->ctrl.last_reply); ftpSendPort(ftpState); return; } ! buf++; /* skip ( */ ! n = sscanf(buf, "%d,%d,%d,%d,%d,%d", &h1, &h2, &h3, &h4, &p1, &p2); ! if (n != 6 || p1 < 0 || p2 < 0 || p1 > 255 || p2 > 255) { ! debug(9, 1) ("Unsafe PASV reply from %s: %s\n", fd_table[ftpState->ctrl.fd].ipaddr, ftpState->ctrl.last_reply); ftpSendPort(ftpState); return; } snprintf(ipaddr, 1024, "%d.%d.%d.%d", h1, h2, h3, h4); if (!safe_inet_addr(ipaddr, NULL)) { ! debug(9, 1) ("Unsafe PASV reply from %s: %s\n", fd_table[ftpState->ctrl.fd].ipaddr, ftpState->ctrl.last_reply); ftpSendPort(ftpState); return; } port = ((p1 << 8) + p2); if (0 == port) { ! debug(9, 1) ("Unsafe PASV reply from %s: %s\n", fd_table[ftpState->ctrl.fd].ipaddr, ftpState->ctrl.last_reply); ftpSendPort(ftpState); return; } if (Config.Ftp.sanitycheck) { if (strcmp(fd_table[ftpState->ctrl.fd].ipaddr, ipaddr) != 0) { ! debug(9, 1) ("Unsafe PASV reply from %s: %s\n", fd_table[ftpState->ctrl.fd].ipaddr, ftpState->ctrl.last_reply); ftpSendPort(ftpState); return; } if (port < 1024) { ! debug(9, 1) ("Unsafe PASV reply from %s: %s\n", fd_table[ftpState->ctrl.fd].ipaddr, ftpState->ctrl.last_reply); ftpSendPort(ftpState); return; } *************** *** 2585,2591 **** snprintf(portbuf, 32, ":%d", request->port); loginbuf[0] = '\0'; if ((int) strlen(request->login) > 0) { ! strcpy(loginbuf, request->login); if ((t = strchr(loginbuf, ':'))) *t = '\0'; strcat(loginbuf, "@"); --- 2604,2610 ---- snprintf(portbuf, 32, ":%d", request->port); loginbuf[0] = '\0'; if ((int) strlen(request->login) > 0) { ! xstrncpy(loginbuf, request->login, sizeof(loginbuf) - 2); if ((t = strchr(loginbuf, ':'))) *t = '\0'; strcat(loginbuf, "@");