-/* Parse through string using state diagram method */
- {
- char ch, zero;
- int i, state;
- u_long a1, a2, a3, a4;
- u_short p1, p2;
-
- a1=0; a2=0; a3=0; a4=0; p1=0; p2=0;
- zero = '0';
- state=-4;
- for (i=0; i<dlen; i++)
- {
- ch = sptr[i];
- switch (state)
- {
- case -4: if (ch == 'P') state=-3; else return; break;
- case -3: if (ch == 'O') state=-2; else return; break;
- case -2: if (ch == 'R') state=-1; else return; break;
- case -1: if (ch == 'T') state= 0; else return; break;
-
- case 0 :
- if (isdigit(ch)) {a1=ch-zero; state=1 ;} break;
- case 1 :
- if (isdigit(ch)) a1=10*a1+ch-zero; else state=2 ; break;
- case 2 :
- if (isdigit(ch)) {a2=ch-zero; state=3 ;} break;
- case 3 :
- if (isdigit(ch)) a2=10*a2+ch-zero; else state=4 ; break;
- case 4 :
- if (isdigit(ch)) {a3=ch-zero; state=5 ;} break;
- case 5 :
- if (isdigit(ch)) a3=10*a3+ch-zero; else state=6 ; break;
- case 6 :
- if (isdigit(ch)) {a4=ch-zero; state=7 ;} break;
- case 7 :
- if (isdigit(ch)) a4=10*a4+ch-zero; else state=8 ; break;
- case 8 :
- if (isdigit(ch)) {p1=ch-zero; state=9 ;} break;
- case 9 :
- if (isdigit(ch)) p1=10*p1+ch-zero; else state=10; break;
- case 10:
- if (isdigit(ch)) {p2=ch-zero; state=11;} break;
- case 11:
- if (isdigit(ch)) p2=10*p2+ch-zero; break;
- }
- }
+/*
+ * Check that data length is not too long and previous message was
+ * properly terminated with CRLF.
+ */
+ if (dlen <= MAX_MESSAGE_SIZE && GetLastLineCrlfTermed(link)) {
+ ftp_message_type = FTP_UNKNOWN_MESSAGE;
+
+ if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER) {
+/*
+ * When aliasing a client, check for the PORT/EPRT command.
+ */
+ if (ParseFtpPortCommand(sptr, dlen))
+ ftp_message_type = FTP_PORT_COMMAND;
+ else if (ParseFtpEprtCommand(sptr, dlen))
+ ftp_message_type = FTP_EPRT_COMMAND;
+ } else {
+/*
+ * When aliasing a server, check for the 227/229 reply.
+ */
+ if (ParseFtp227Reply(sptr, dlen))
+ ftp_message_type = FTP_227_REPLY;
+ else if (ParseFtp229Reply(sptr, dlen))
+ ftp_message_type = FTP_229_REPLY;
+ }
+
+ if (ftp_message_type != FTP_UNKNOWN_MESSAGE)
+ NewFtpMessage(pip, link, maxpacketsize, ftp_message_type);
+ }
+
+/* Track the msgs which are CRLF term'd for PORT/PASV FW breach */
+
+ if (dlen) { /* only if there's data */
+ sptr = (char *) pip; /* start over at beginning */
+ tlen = ntohs(pip->ip_len); /* recalc tlen, pkt may have grown */
+ SetLastLineCrlfTermed(link,
+ (sptr[tlen-2] == '\r') && (sptr[tlen-1] == '\n'));
+ }
+}
+
+static int
+ParseFtpPortCommand(char *sptr, int dlen)
+{
+ char ch;
+ int i, state;
+ u_int32_t addr;
+ u_short port;
+ u_int8_t octet;
+
+ /* Format: "PORT A,D,D,R,PO,RT". */
+
+ /* Return if data length is too short. */
+ if (dlen < 18)
+ return 0;
+
+ addr = port = octet = 0;
+ state = -4;
+ for (i = 0; i < dlen; i++) {
+ ch = sptr[i];
+ switch (state) {
+ case -4: if (ch == 'P') state++; else return 0; break;
+ case -3: if (ch == 'O') state++; else return 0; break;
+ case -2: if (ch == 'R') state++; else return 0; break;
+ case -1: if (ch == 'T') state++; else return 0; break;
+
+ case 0:
+ if (isspace(ch))
+ break;
+ else
+ state++;
+ case 1: case 3: case 5: case 7: case 9: case 11:
+ if (isdigit(ch)) {
+ octet = ch - '0';
+ state++;
+ } else
+ return 0;
+ break;
+ case 2: case 4: case 6: case 8:
+ if (isdigit(ch))
+ octet = 10 * octet + ch - '0';
+ else if (ch == ',') {
+ addr = (addr << 8) + octet;
+ state++;
+ } else
+ return 0;
+ break;
+ case 10: case 12:
+ if (isdigit(ch))
+ octet = 10 * octet + ch - '0';
+ else if (ch == ',' || state == 12) {
+ port = (port << 8) + octet;
+ state++;
+ } else
+ return 0;
+ break;
+ }
+ }
+
+ if (state == 13) {
+ true_addr.s_addr = htonl(addr);
+ true_port = port;
+ return 1;
+ } else
+ return 0;
+}
+
+static int
+ParseFtpEprtCommand(char *sptr, int dlen)
+{
+ char ch, delim;
+ int i, state;
+ u_int32_t addr;
+ u_short port;
+ u_int8_t octet;
+
+ /* Format: "EPRT |1|A.D.D.R|PORT|". */
+
+ /* Return if data length is too short. */
+ if (dlen < 18)
+ return 0;
+
+ addr = port = octet = 0;
+ delim = '|'; /* XXX gcc -Wuninitialized */
+ state = -4;
+ for (i = 0; i < dlen; i++) {
+ ch = sptr[i];
+ switch (state)
+ {
+ case -4: if (ch == 'E') state++; else return 0; break;
+ case -3: if (ch == 'P') state++; else return 0; break;
+ case -2: if (ch == 'R') state++; else return 0; break;
+ case -1: if (ch == 'T') state++; else return 0; break;
+
+ case 0:
+ if (!isspace(ch)) {
+ delim = ch;
+ state++;
+ }
+ break;
+ case 1:
+ if (ch == '1') /* IPv4 address */
+ state++;
+ else
+ return 0;
+ break;
+ case 2:
+ if (ch == delim)
+ state++;
+ else
+ return 0;
+ break;
+ case 3: case 5: case 7: case 9:
+ if (isdigit(ch)) {
+ octet = ch - '0';
+ state++;
+ } else
+ return 0;
+ break;
+ case 4: case 6: case 8: case 10:
+ if (isdigit(ch))
+ octet = 10 * octet + ch - '0';
+ else if (ch == '.' || state == 10) {
+ addr = (addr << 8) + octet;
+ state++;
+ } else
+ return 0;
+ break;
+ case 11:
+ if (isdigit(ch)) {
+ port = ch - '0';
+ state++;
+ } else
+ return 0;
+ break;
+ case 12:
+ if (isdigit(ch))
+ port = 10 * port + ch - '0';
+ else if (ch == delim)
+ state++;
+ else
+ return 0;
+ break;
+ }
+ }
+
+ if (state == 13) {
+ true_addr.s_addr = htonl(addr);
+ true_port = port;
+ return 1;
+ } else
+ return 0;
+}