diff --git a/ncat/ncat_connect.c b/ncat/ncat_connect.c index 89d4ebdca..aa60b556c 100644 --- a/ncat/ncat_connect.c +++ b/ncat/ncat_connect.c @@ -1381,7 +1381,7 @@ static void read_socket_handler(nsock_pool nsp, nsock_event evt, void *data) ncat_delay_timer(o.linedelay); if (o.telnet) - dotelnet(nsock_iod_get_sd(nse_iod(evt)), (unsigned char *) buf, nbytes); + dotelnet(nsock_iod_get_sd(nse_iod(evt)), (unsigned char *) buf, &nbytes); /* Write socket data to stdout */ Write(STDOUT_FILENO, buf, nbytes); diff --git a/ncat/ncat_core.c b/ncat/ncat_core.c index ee8d7c6f2..50fc4309e 100644 --- a/ncat/ncat_core.c +++ b/ncat/ncat_core.c @@ -370,7 +370,7 @@ int ncat_recv(struct fdinfo *fdn, char *buf, size_t size, int *pending) if (o.linedelay) ncat_delay_timer(o.linedelay); if (o.telnet) - dotelnet(fdn->fd, (unsigned char *) buf, n); + dotelnet(fdn->fd, (unsigned char *) buf, &n); ncat_log_recv(buf, n); /* SSL can buffer our input, so doing another select() won't necessarily @@ -470,29 +470,59 @@ int ncat_broadcast(fd_set *fds, const fd_list_t *fdlist, const char *msg, size_t } /* Do telnet WILL/WONT DO/DONT negotiations */ -void dotelnet(int s, unsigned char *buf, size_t bufsiz) +void dotelnet(int s, unsigned char *buf, int *bufsiz) { - unsigned char *end = buf + bufsiz, *p; - unsigned char tbuf[3]; + unsigned char *end = buf + *bufsiz; + unsigned char *q = buf; + unsigned char *p = buf; + unsigned char tbuf[3] = {0xff, 0, 0}; - for (p = buf; buf < end; p++) { + /* RFC 854: + * 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. + */ + for (p = buf; p < end; p++) { if (*p != 255) /* IAC */ + { + *q++ = *p; + continue; + } + + p++; if (p >= end) break; + switch (*p) { + /* Answer DONT for WILL or WONT */ + case 251: + case 252: + tbuf[1] = 254; break; - tbuf[0] = *p++; - - /* Answer DONT for WILL or WONT */ - if (*p == 251 || *p == 252) - tbuf[1] = 254; - - /* Answer WONT for DO or DONT */ - else if (*p == 253 || *p == 254) + /* Answer WONT for DO or DONT */ + case 253: + case 254: tbuf[1] = 252; + break; - tbuf[2] = *++p; + /* IAC escaped data byte 255 */ + case 255: + *q++ = 255; + continue; + break; + + /* Unhandled command; ignore */ + default: + continue; + break; + } + + p++; if (p >= end) break; + tbuf[2] = *p; send(s, (const char *) tbuf, 3, 0); } + // Adjust length for deleted IAC sequences + *bufsiz = q - buf; } /* sleep(), usleep(), msleep(), Sleep() -- all together now, "portability". diff --git a/ncat/ncat_core.h b/ncat/ncat_core.h index 0bd8cc9ff..720c6fc73 100644 --- a/ncat/ncat_core.h +++ b/ncat/ncat_core.h @@ -213,7 +213,7 @@ int ncat_send(struct fdinfo *fdn, const char *buf, size_t size); extern int ncat_broadcast(fd_set *fds, const fd_list_t *fdlist, const char *msg, size_t size); /* Do telnet WILL/WONT DO/DONT negotiations */ -extern void dotelnet(int s, unsigned char *buf, size_t bufsiz); +extern void dotelnet(int s, unsigned char *buf, int *bufsiz); /* sleep(), usleep(), msleep(), Sleep() -- all together now, "portability". *