From 538214996a0bc219481a444c421bcda3a0287b69 Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Fri, 11 Aug 2017 21:52:42 -0700 Subject: [PATCH] Implement incoming NVT EOL translation in process() The translation is enabled by a new bit in telnet_init() flags parameter. Remove telnet_translate_eol() since that function is subsumed. --- README | 14 ++++------ libtelnet.c | 77 +++++++++++++++++++++-------------------------------- libtelnet.h | 17 +++--------- 3 files changed, 39 insertions(+), 69 deletions(-) diff --git a/README b/README index 73b58d2..9fad6ca 100644 --- a/README +++ b/README @@ -123,6 +123,11 @@ IIa. Initialization Operate in proxy mode. This disables the RFC1143 support and enables automatic detection of COMPRESS2 streams. + TELNET_FLAG_NVT_EOL + Receive data with translation of the TELNET NVT CR NUL and CR LF + sequences specified in RFC854 to C carriage return (\r) and C + newline (\n), respectively. + If telnet_init() fails to allocate the required memory, the returned pointer will be zero. @@ -145,15 +150,6 @@ IIb. Receiving Data triggered for any regular data such as user input or server process output. - size_t telnet_translate_eol(telnet_t *telnet, - char *buffer, size_t size, int *eol_was_split); - Scans a buffer received in a TELNET_EV_DATA event to translate the - TELNET NVT CR NUL and CR LF sequences specified in RFC854 to C - carriage return (\r) and C newline (\n), respectively. Sequences - split across a buffer boundary are handled using the eol_was_split - flag that should be initialized to 0 before the first call. The - possibly shorter length of the text after translation is returned. - IIc. Sending Data All of the output functions will invoke the TELNET_EV_SEND event. diff --git a/libtelnet.c b/libtelnet.c index 21af4da..89704f3 100644 --- a/libtelnet.c +++ b/libtelnet.c @@ -64,6 +64,7 @@ /* telnet state codes */ enum telnet_state_t { TELNET_STATE_DATA = 0, + TELNET_STATE_EOL, TELNET_STATE_IAC, TELNET_STATE_WILL, TELNET_STATE_WONT, @@ -105,10 +106,6 @@ struct telnet_t { unsigned char q_size; }; -/* Internal-only bits in option flags */ -#define TELNET_FLAG_TRANSMIT_BINARY (1<<1) -#define TELNET_FLAG_RECEIVE_BINARY (1<<2) - /* RFC1143 option negotiation state */ typedef struct telnet_rfc1143_t { unsigned char telopt; @@ -978,9 +975,38 @@ static void _process(telnet_t *telnet, const char *buffer, size_t size) { telnet->eh(telnet, &ev, telnet->ud); } telnet->state = TELNET_STATE_IAC; + } else if (byte == '\r' && + (telnet->flags & TELNET_FLAG_NVT_EOL) && + !(telnet->flags & TELNET_FLAG_RECEIVE_BINARY)) { + if (i != start) { + ev.type = TELNET_EV_DATA; + ev.data.buffer = buffer + start; + ev.data.size = i - start; + telnet->eh(telnet, &ev, telnet->ud); + } + telnet->state = TELNET_STATE_EOL; } break; + /* NVT EOL to be translated */ + case TELNET_STATE_EOL: + if (byte != '\n') { + byte = '\r'; + ev.type = TELNET_EV_DATA; + ev.data.buffer = (char*)&byte; + ev.data.size = 1; + telnet->eh(telnet, &ev, telnet->ud); + byte = buffer[i]; + } + // any byte following '\r' other than '\n' or '\0' is invalid, + // so pass both \r and the byte + start = i; + if (byte == '\0') + ++start; + /* state update */ + telnet->state = TELNET_STATE_DATA; + break; + /* IAC command */ case TELNET_STATE_IAC: switch (byte) { @@ -1137,49 +1163,6 @@ static void _process(telnet_t *telnet, const char *buffer, size_t size) { } } -/* perform NVT end-of-line translation for received text */ -size_t telnet_translate_eol(telnet_t *telnet, char *buffer, size_t size, - int *eol_was_split) { - size_t i = 0, l = 0; - if (size == 0) - return size; - - /* no translation if in BINARY mode */ - if (telnet->flags & TELNET_FLAG_RECEIVE_BINARY) - return size; - - /* fix up translation if split across buffer boundary */ - if (*eol_was_split) { - /* CR-NUL translates to \r which was skipped at end of previous */ - /* buffer, while CR-LF translates to \n, so just leave it */ - if (buffer[i] == '\0') { - buffer[i] = '\r'; - } - ++i; - } - - for ( ; i < size-1; ++i, ++l) { - buffer[l] = buffer[i]; - if (buffer[i] == '\r') { - if (buffer[i+1] == '\n') { - /* CR-LF translates to \n */ - buffer[l] = '\n'; - ++i; - } else if (buffer[i+1] == '\0') { - /* CR-NUL translates to \r */ - ++i; - } - } - } - if (buffer[i] == '\r') { - --l; - *eol_was_split = 1; - } else { - *eol_was_split = 0; - } - return l + 1; -} - /* push a bytes into the state tracker */ void telnet_recv(telnet_t *telnet, const char *buffer, size_t size) { diff --git a/libtelnet.h b/libtelnet.h index 984b35f..1754ec4 100644 --- a/libtelnet.h +++ b/libtelnet.h @@ -175,7 +175,11 @@ typedef struct telnet_telopt_t telnet_telopt_t; /*@{*/ /*! Control behavior of telnet state tracker. */ #define TELNET_FLAG_PROXY (1<<0) +#define TELNET_FLAG_NVT_EOL (1<<1) +/* Internal-only bits in option flags */ +#define TELNET_FLAG_TRANSMIT_BINARY (1<<5) +#define TELNET_FLAG_RECEIVE_BINARY (1<<6) #define TELNET_PFLAG_DEFLATE (1<<7) /*@}*/ @@ -445,19 +449,6 @@ extern void telnet_send(telnet_t *telnet, extern void telnet_send_text(telnet_t *telnet, const char *buffer, size_t size); -/*! - * Translate NVT EOL byte sequences into local characters - * (CR-NUL -> \\r and CR-LF -> \\n) unless in BINARY mode. - * - * \param telnet Telnet state tracker object. - * \param buffer Buffer of bytes to translate. - * \param size Number of bytes to translate. - * \param split 1 if in the middle of EOL byte pair at start/end. - * \return Number of bytes after translation. - */ -extern size_t telnet_translate_eol(telnet_t *telnet, - char *buffer, size_t size, int *split); - /*! * \brief Begin a sub-negotiation command. *