Commits (3)
  • Deucе's avatar
    Fix outgoing telnet expension · cfb87774
    Deucе authored
    This is what was breaking uploads via telnet.  Not only was it sending
    the unexpanded buffer, it was also sending the length of the expanded
    buffer out of it (wandering into gibberish or at worst, outside of the
    buffer).
    cfb87774
  • Deucе's avatar
    Move telnet_expand() into SyncTERM proper. · 9db9df4a
    Deucе authored
    This allows ensuring we don't expand CRLF into CRLFLF.  This is
    usually harmless, but there's no real need to put up with it in
    a program with a single thread using the expand function.
    9db9df4a
  • Deucе's avatar
    Whitespace cleanup · 83659316
    Deucе authored
    83659316
......@@ -326,8 +326,9 @@ int conn_send(const void *vbuffer, size_t buflen, unsigned int timeout)
pthread_mutex_lock(&(conn_outbuf.mutex));
found=conn_buf_wait_free(&conn_outbuf, obuflen, timeout);
if(found)
found=conn_buf_put(&conn_outbuf, buffer, found);
if(found) {
found=conn_buf_put(&conn_outbuf, expanded, found);
}
pthread_mutex_unlock(&(conn_outbuf.mutex));
if (conn_api.tx_parse_cb != NULL) {
......
......@@ -2,6 +2,7 @@
/* $Id: conn_telnet.c,v 1.18 2020/05/03 20:12:42 deuce Exp $ */
#include <stdbool.h>
#include <stdlib.h>
#include "gen_defs.h"
......@@ -19,6 +20,65 @@
extern int telnet_log_level;
/*****************************************************************************/
// Escapes Telnet IACs in 'inbuf' by doubling the IAC char
// 'result' may point to either inbuf (if there were no IACs) or outbuf
// Returns the final byte count of the result
/*****************************************************************************/
size_t st_telnet_expand(const uchar* inbuf, size_t inlen, uchar* outbuf, size_t outlen, BOOL expand_cr, uchar** result)
{
static bool last_was_lf = false;
BYTE* first_iac = (BYTE*)memchr(inbuf, TELNET_IAC, inlen);
BYTE* first_cr=NULL;
if (inlen == 0) {
if (result != NULL)
*result = (uchar *)inbuf;
return 0;
}
if (last_was_lf && inbuf[0] == '\n') {
inbuf++;
inlen--;
}
last_was_lf = false;
if (expand_cr)
first_cr = (BYTE*)memchr(inbuf, '\r', inlen);
else
last_was_lf = false;
if (first_iac == NULL && first_cr == NULL) { /* Nothing to expand */
if (result != NULL)
*result = (uchar*)inbuf;
return inlen;
}
size_t o;
if(first_iac != NULL && (first_cr == NULL || first_iac < first_cr))
o = first_iac - inbuf;
else
o = first_cr - inbuf;
memcpy(outbuf, inbuf, o);
for (size_t i = o; i < inlen && o < outlen; i++) {
if (inbuf[i] == '\n' && last_was_lf)
continue;
last_was_lf = false;
if(inbuf[i] == TELNET_IAC)
outbuf[o++] = TELNET_IAC;
if(o >= outlen)
break;
outbuf[o++] = inbuf[i];
if(expand_cr && inbuf[i] == '\r' && o < outlen) {
last_was_lf = true;
outbuf[o++] = '\n'; // See RFC5198
}
}
if(result != NULL)
*result = outbuf;
return o;
}
void *telnet_rx_parse_cb(const void *buf, size_t inlen, size_t *olen)
{
// telnet_interpret() can add up to one byte to inbuf ('\r')
......@@ -36,7 +96,7 @@ void *telnet_tx_parse_cb(const void *buf, size_t len, size_t *olen)
void *ret = malloc(len * 2);
void *parsed;
*olen = telnet_expand(buf, len, ret, len * 2
*olen = st_telnet_expand(buf, len, ret, len * 2
,telnet_local_option[TELNET_BINARY_TX]!=TELNET_DO, (BYTE **)&parsed);
if (parsed != ret)
......
......@@ -95,7 +95,7 @@ BYTE* telnet_interpret(BYTE* inbuf, size_t inlen, BYTE* outbuf, size_t *outlen)
return(inbuf); /* no length? No interpretation */
}
first_int=(BYTE*)memchr(inbuf, TELNET_IAC, inlen);
first_int=(BYTE*)memchr(inbuf, TELNET_IAC, inlen);
if(telnet_remote_option[TELNET_BINARY_TX]!=TELNET_WILL) {
first_cr=(BYTE*)memchr(inbuf, '\r', inlen);
if(first_cr) {
......@@ -104,23 +104,23 @@ BYTE* telnet_interpret(BYTE* inbuf, size_t inlen, BYTE* outbuf, size_t *outlen)
}
}
if(telnet_cmdlen==0 && first_int==NULL) {
*outlen=inlen;
return(inbuf); /* no interpretation needed */
}
if(telnet_cmdlen==0 && first_int==NULL) {
*outlen=inlen;
return(inbuf); /* no interpretation needed */
}
if(telnet_cmdlen==0 /* If we haven't returned and telnet_cmdlen==0 then first_int is not NULL */ ) {
*outlen=first_int-inbuf;
memcpy(outbuf, inbuf, *outlen);
} else
*outlen=0;
if(telnet_cmdlen==0 /* If we haven't returned and telnet_cmdlen==0 then first_int is not NULL */ ) {
*outlen=first_int-inbuf;
memcpy(outbuf, inbuf, *outlen);
} else
*outlen=0;
for(i=*outlen;i<inlen;i++) {
for(i=*outlen;i<inlen;i++) {
if(telnet_remote_option[TELNET_BINARY_TX]!=TELNET_WILL) {
if(telnet_cmdlen==1 && telnet_cmd[0]=='\r') {
outbuf[(*outlen)++]='\r';
outbuf[(*outlen)++]='\r';
if(inbuf[i]!=0 && inbuf[i]!=TELNET_IAC)
outbuf[(*outlen)++]=inbuf[i];
outbuf[(*outlen)++]=inbuf[i];
telnet_cmdlen=0;
if(inbuf[i]!=TELNET_IAC)
continue;
......@@ -131,12 +131,12 @@ BYTE* telnet_interpret(BYTE* inbuf, size_t inlen, BYTE* outbuf, size_t *outlen)
}
}
if(inbuf[i]==TELNET_IAC && telnet_cmdlen==1) { /* escaped 255 */
telnet_cmdlen=0;
outbuf[(*outlen)++]=TELNET_IAC;
continue;
}
if(inbuf[i]==TELNET_IAC || telnet_cmdlen) {
if(inbuf[i]==TELNET_IAC && telnet_cmdlen==1) { /* escaped 255 */
telnet_cmdlen=0;
outbuf[(*outlen)++]=TELNET_IAC;
continue;
}
if(inbuf[i]==TELNET_IAC || telnet_cmdlen) {
if(telnet_cmdlen<sizeof(telnet_cmd))
telnet_cmd[telnet_cmdlen++]=inbuf[i];
......@@ -163,10 +163,10 @@ BYTE* telnet_interpret(BYTE* inbuf, size_t inlen, BYTE* outbuf, size_t *outlen)
telnet_cmdlen=0;
}
}
else if(telnet_cmdlen==2 && inbuf[i]<TELNET_WILL) {
telnet_cmdlen=0;
}
else if(telnet_cmdlen>=3) { /* telnet option negotiation */
else if(telnet_cmdlen==2 && inbuf[i]<TELNET_WILL) {
telnet_cmdlen=0;
}
else if(telnet_cmdlen>=3) { /* telnet option negotiation */
lprintf(LOG_INFO,"RX: %s %s"
,telnet_cmd_desc(command),telnet_opt_desc(option));
......@@ -236,4 +236,3 @@ BYTE* telnet_interpret(BYTE* inbuf, size_t inlen, BYTE* outbuf, size_t *outlen)
}
return(outbuf);
}