diff -Naur busybox-1.8.2_org/networking/telnetd.c busybox-1.8.2/networking/telnetd.c --- busybox-1.8.2_org/networking/telnetd.c 2007-11-10 02:54:22.000000000 +0100 +++ busybox-1.8.2/networking/telnetd.c 2008-07-15 09:52:47.000000000 +0200 @@ -26,7 +26,7 @@ #include "libbb.h" #if DEBUG -#define TELCMDS +#define TELCMDS "" #define TELOPTS #endif #include @@ -47,6 +47,9 @@ #define TS_BUF2 (((unsigned char*)(ts + 1)) + BUFSIZE) int rdidx1, wridx1, size1; int rdidx2, wridx2, size2; + /*--- State for remove telnet-cmds ---*/ + enum {State_NonIAC, State_IAC, State_CmdwithOption, State_SB_Start, State_SB, State_SB_IAC} state; + unsigned char tmp[4], tmp_count; }; /* Two buffers are directly after tsession in malloced memory. @@ -85,6 +88,26 @@ CR-LF ->'s CR mapping is also done here, for convenience. NB: may fail to remove iacs which wrap around buffer! + + mbahr: Changed on 13.08.2008: + IAC escape IAC + Complete handling of IAC, so that 2- or 3-byte-cmds + will removed and also always in area IAC SB until IAC SE, + because RFC-854 says: + > All TELNET commands consist of at least a two byte sequence: the + >"Interpret as Command" (IAC) escape character followed by the code + >for the command. The commands dealing with option negotiation are + >three byte sequences, the third byte being the code for the option + >referenced. This format was chosen so that as more comprehensive use + >of the "data space" is made -- by negotiations from the basic NVT, of + >course -- collisions of data bytes with reserved command values will + >be minimized, all such collisions requiring the inconvenience, and + >inefficiency, of "escaping" the data bytes into the stream. With the + >current set-up, only the IAC need be doubled to be sent as data, and + >the other 255 codes may be passed transparently. + + Fixme: the actually version do not filter 0xff for send to socket, so echo + of 0xFF can confuse client! */ static unsigned char * remove_iacs(struct tsession *ts, int *pnum_totty) @@ -93,54 +116,90 @@ unsigned char *ptr = ptr0; unsigned char *totty = ptr; unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1); - int num_totty; + int num_totty, flag =0; while (ptr < end) { - if (*ptr != IAC) { - char c = *ptr; - - *totty++ = c; - ptr++; - /* We now map \r\n ==> \r for pragmatic reasons. - * Many client implementations send \r\n when - * the user hits the CarriageReturn key. - */ - if (c == '\r' && ptr < end && (*ptr == '\n' || *ptr == '\0')) - ptr++; - } else { - /* - * TELOPT_NAWS support! - */ - if ((ptr+2) >= end) { - /* only the beginning of the IAC is in the - buffer we were asked to process, we can't - process this char. */ - break; - } - - /* - * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE - */ - else if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) { - struct winsize ws; - - if ((ptr+8) >= end) - break; /* incomplete, can't process */ - ws.ws_col = (ptr[3] << 8) | ptr[4]; - ws.ws_row = (ptr[5] << 8) | ptr[6]; - ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws); - ptr += 9; - } else { - /* skip 3-byte IAC non-SB cmd */ + switch(ts->state) { + case State_NonIAC: + if (*ptr != IAC) { + *totty++ = *ptr; + /* We now map \r\n ==> \r for pragmatic reasons. + * Many client implementations send \r\n when + * the user hits the CarriageReturn key. + */ + if (*ptr == '\r' && (*(ptr+1) == '\n' || *(ptr+1) == 0) && (ptr+1) < end) + ptr++; + break; + } + ts->state = State_IAC; + break; + case State_IAC: + switch(*ptr) { + case IAC: + *totty++ = *ptr; /*--- 0xFF for terminal ---*/ + ts->state = State_NonIAC; + break; + case DONT: + case DO: + case WONT: + case WILL: #if DEBUG - fprintf(stderr, "Ignoring IAC %s,%s\n", - TELCMD(ptr[1]), TELOPT(ptr[2])); + fprintf(stderr, "Ignoring IAC %s\n", TELCMDS(*ptr)); #endif - ptr += 3; - } - } - } - + ts->state = State_CmdwithOption; + break; + case SB: + /*--- Subnegation begins, end with SE ---*/ + ts->state = State_SB_Start; + break; + default: + /*--- only 2 byte Command -> skip ---*/ +#if DEBUG + fprintf(stderr, "Ignoring IAC %s\n", TELCMDS(*ptr)); +#endif + ts->state = State_NonIAC; + } + break; + case State_CmdwithOption: + /*--- ignore option ---*/ + ts->state = State_NonIAC; + break; + case State_SB_Start: + /* TELOPT_NAWS support! */ + /* TELOPT_NAWS -> 4-byte */ + if(*ptr == TELOPT_NAWS) { + struct winsize ws; + int tail = MIN(4 - ts->tmp_count, end - ptr - 1); + memcpy(&ts->tmp[ts->tmp_count], ptr + 1, tail); + ts->tmp_count += tail; + if(ts->tmp_count < 4) { + ptr = end; + break; /* incomplete, can't process */ + } + ws.ws_col = (ts->tmp[0] << 8) | ts->tmp[1]; + ws.ws_row = (ts->tmp[2] << 8) | ts->tmp[3]; + (void) ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws); + ts->tmp_count = 0; + ptr += tail; + } + ts->state = State_SB; + break; + case State_SB: + if (*ptr == IAC) { + ts->state = State_SB_IAC; + } + break; + case State_SB_IAC: + if (*ptr == SE) { + /*--- SE found ---*/ + ts->state = State_NonIAC; + break; + } + ts->state = State_SB; + break; + } + ptr++; + } num_totty = totty - ptr0; *pnum_totty = num_totty; /* the difference between ptr and totty is number of iacs