LCOV - code coverage report
Current view: top level - libs/libtelnet - libtelnet.c (source / functions) Coverage Total Hit
Test: MagAOX Lines: 0.0 % 713 0
Test Date: 2026-01-03 21:03:39 Functions: 0.0 % 37 0

            Line data    Source code
       1              : /*
       2              :  * libtelnet - TELNET protocol handling library
       3              :  *
       4              :  * Sean Middleditch
       5              :  * sean@sourcemud.org
       6              :  *
       7              :  * The author or authors of this code dedicate any and all copyright interest
       8              :  * in this code to the public domain. We make this dedication for the benefit
       9              :  * of the public at large and to the detriment of our heirs and successors. We
      10              :  * intend this dedication to be an overt act of relinquishment in perpetuity of
      11              :  * all present and future rights to this code under copyright law.
      12              :  */
      13              : 
      14              : #ifdef HAVE_CONFIG_H
      15              : #include <config.h>
      16              : #endif
      17              : #include <stdlib.h>
      18              : #include <string.h>
      19              : #include <stdio.h>
      20              : #include <errno.h>
      21              : #include <string.h>
      22              : #include <stdarg.h>
      23              : 
      24              : /* Win32 compatibility */
      25              : #if defined(_WIN32)
      26              : # define vsnprintf _vsnprintf
      27              : # define __func__ __FUNCTION__
      28              : # define ZLIB_WINAPI 1
      29              : # if defined(_MSC_VER)
      30              : /* va_copy() is directly supported starting in Visual Studio 2013
      31              :  * https://msdn.microsoft.com/en-us/library/kb57fad8(v=vs.110).aspx
      32              :  * https://msdn.microsoft.com/en-us/library/kb57fad8(v=vs.120).aspx
      33              :  */
      34              : #  if _MSC_VER <= 1700
      35              : #   define va_copy(dest, src) (dest = src)
      36              : #  endif
      37              : # endif
      38              : #endif
      39              : 
      40              : #if defined(HAVE_ZLIB)
      41              : # include <zlib.h>
      42              : #endif
      43              : 
      44              : #include "libtelnet.h"
      45              : 
      46              : /* inlinable functions */
      47              : #if defined(__GNUC__) || __STDC_VERSION__ >= 199901L
      48              : # define INLINE __inline__
      49              : #else
      50              : # define INLINE
      51              : #endif
      52              : 
      53              : /* helper for Q-method option tracking */
      54              : #define Q_US(q) ((q).state & 0x0F)
      55              : #define Q_HIM(q) (((q).state & 0xF0) >> 4)
      56              : #define Q_MAKE(us,him) ((us) | ((him) << 4))
      57              : 
      58              : /* helper for the negotiation routines */
      59              : #define NEGOTIATE_EVENT(telnet,cmd,opt) \
      60              :         ev.type = (cmd); \
      61              :         ev.neg.telopt = (opt); \
      62              :         (telnet)->eh((telnet), &ev, (telnet)->ud);
      63              : 
      64              : /* telnet state codes */
      65              : enum telnet_state_t {
      66              :         TELNET_STATE_DATA = 0,
      67              :         TELNET_STATE_EOL,
      68              :         TELNET_STATE_IAC,
      69              :         TELNET_STATE_WILL,
      70              :         TELNET_STATE_WONT,
      71              :         TELNET_STATE_DO,
      72              :         TELNET_STATE_DONT,
      73              :         TELNET_STATE_SB,
      74              :         TELNET_STATE_SB_DATA,
      75              :         TELNET_STATE_SB_DATA_IAC
      76              : };
      77              : typedef enum telnet_state_t telnet_state_t;
      78              : 
      79              : /* telnet state tracker */
      80              : struct telnet_t {
      81              :         /* user data */
      82              :         void *ud;
      83              :         /* telopt support table */
      84              :         const telnet_telopt_t *telopts;
      85              :         /* event handler */
      86              :         telnet_event_handler_t eh;
      87              : #if defined(HAVE_ZLIB)
      88              :         /* zlib (mccp2) compression */
      89              :         z_stream *z;
      90              : #endif
      91              :         /* RFC1143 option negotiation states */
      92              :         struct telnet_rfc1143_t *q;
      93              :         /* sub-request buffer */
      94              :         char *buffer;
      95              :         /* current size of the buffer */
      96              :         size_t buffer_size;
      97              :         /* current buffer write position (also length of buffer data) */
      98              :         size_t buffer_pos;
      99              :         /* current state */
     100              :         enum telnet_state_t state;
     101              :         /* option flags */
     102              :         unsigned char flags;
     103              :         /* current subnegotiation telopt */
     104              :         unsigned char sb_telopt;
     105              :         /* length of RFC1143 queue */
     106              :         unsigned char q_size;
     107              : };
     108              : 
     109              : /* RFC1143 option negotiation state */
     110              : typedef struct telnet_rfc1143_t {
     111              :         unsigned char telopt;
     112              :         unsigned char state;
     113              : } telnet_rfc1143_t;
     114              : 
     115              : /* RFC1143 state names */
     116              : #define Q_NO 0
     117              : #define Q_YES 1
     118              : #define Q_WANTNO 2
     119              : #define Q_WANTYES 3
     120              : #define Q_WANTNO_OP 4
     121              : #define Q_WANTYES_OP 5
     122              : 
     123              : /* telnet NVT EOL sequences */
     124              : static const char CRLF[] = { '\r', '\n' };
     125              : static const char CRNUL[] = { '\r', '\0' };
     126              : 
     127              : /* buffer sizes */
     128              : static const size_t _buffer_sizes[] = { 0, 512, 2048, 8192, 16384, };
     129              : static const size_t _buffer_sizes_count = sizeof(_buffer_sizes) /
     130              :                 sizeof(_buffer_sizes[0]);
     131              : 
     132              : /* error generation function */
     133            0 : static telnet_error_t _error(telnet_t *telnet, unsigned line,
     134              :                 const char* func, telnet_error_t err, int fatal, const char *fmt,
     135              :                 ...) {
     136              :         telnet_event_t ev;
     137              :         char buffer[512];
     138              :         va_list va;
     139              : 
     140              :         /* format informational text */
     141            0 :         va_start(va, fmt);
     142            0 :         vsnprintf(buffer, sizeof(buffer), fmt, va);
     143            0 :         va_end(va);
     144              : 
     145              :         /* send error event to the user */
     146            0 :         ev.type = fatal ? TELNET_EV_ERROR : TELNET_EV_WARNING;
     147            0 :         ev.error.file = __FILE__;
     148            0 :         ev.error.func = func;
     149            0 :         ev.error.line = line;
     150            0 :         ev.error.msg = buffer;
     151            0 :         telnet->eh(telnet, &ev, telnet->ud);
     152              : 
     153            0 :         return err;
     154              : }
     155              : 
     156              : #if defined(HAVE_ZLIB)
     157              : /* initialize the zlib box for a telnet box; if deflate is non-zero, it
     158              :  * initializes zlib for delating (compression), otherwise for inflating
     159              :  * (decompression).  returns TELNET_EOK on success, something else on
     160              :  * failure.
     161              :  */
     162              : telnet_error_t _init_zlib(telnet_t *telnet, int deflate, int err_fatal) {
     163              :         z_stream *z;
     164              :         int rs;
     165              : 
     166              :         /* if compression is already enabled, fail loudly */
     167              :         if (telnet->z != 0)
     168              :                 return _error(telnet, __LINE__, __func__, TELNET_EBADVAL,
     169              :                                 err_fatal, "cannot initialize compression twice");
     170              : 
     171              :         /* allocate zstream box */
     172              :         if ((z= (z_stream *)calloc(1, sizeof(z_stream))) == 0)
     173              :                 return _error(telnet, __LINE__, __func__, TELNET_ENOMEM, err_fatal,
     174              :                                 "malloc() failed: %s", strerror(errno));
     175              : 
     176              :         /* initialize */
     177              :         if (deflate) {
     178              :                 if ((rs = deflateInit(z, Z_DEFAULT_COMPRESSION)) != Z_OK) {
     179              :                         free(z);
     180              :                         return _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS,
     181              :                                         err_fatal, "deflateInit() failed: %s", zError(rs));
     182              :                 }
     183              :                 telnet->flags |= TELNET_PFLAG_DEFLATE;
     184              :         } else {
     185              :                 if ((rs = inflateInit(z)) != Z_OK) {
     186              :                         free(z);
     187              :                         return _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS,
     188              :                                         err_fatal, "inflateInit() failed: %s", zError(rs));
     189              :                 }
     190              :                 telnet->flags &= ~TELNET_PFLAG_DEFLATE;
     191              :         }
     192              : 
     193              :         telnet->z = z;
     194              : 
     195              :         return TELNET_EOK;
     196              : }
     197              : #endif /* defined(HAVE_ZLIB) */
     198              : 
     199              : /* push bytes out, compressing them first if need be */
     200            0 : static void _send(telnet_t *telnet, const char *buffer,
     201              :                 size_t size) {
     202              :         telnet_event_t ev;
     203              : 
     204              : #if defined(HAVE_ZLIB)
     205              :         /* if we have a deflate (compression) zlib box, use it */
     206              :         if (telnet->z != 0 && telnet->flags & TELNET_PFLAG_DEFLATE) {
     207              :                 char deflate_buffer[1024];
     208              : 
     209              : 
     210              :                 /* initialize z state */
     211              :                 telnet->z->next_in = (unsigned char *)buffer;
     212              :                 telnet->z->avail_in = (unsigned int)size;
     213              :                 telnet->z->next_out = (unsigned char *)deflate_buffer;
     214              :                 telnet->z->avail_out = sizeof(deflate_buffer);
     215              : 
     216              :                 /* deflate until buffer exhausted and all output is produced */
     217              :                 while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) {
     218              :            int rs;
     219              :                         /* compress */
     220              :                         if ((rs = deflate(telnet->z, Z_SYNC_FLUSH)) != Z_OK) {
     221              :                                 _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, 1,
     222              :                                                 "deflate() failed: %s", zError(rs));
     223              :                                 deflateEnd(telnet->z);
     224              :                                 free(telnet->z);
     225              :                                 telnet->z = 0;
     226              :                                 break;
     227              :                         }
     228              : 
     229              :                         /* send event */
     230              :                         ev.type = TELNET_EV_SEND;
     231              :                         ev.data.buffer = deflate_buffer;
     232              :                         ev.data.size = sizeof(deflate_buffer) - telnet->z->avail_out;
     233              :                         telnet->eh(telnet, &ev, telnet->ud);
     234              : 
     235              :                         /* prepare output buffer for next run */
     236              :                         telnet->z->next_out = (unsigned char *)deflate_buffer;
     237              :                         telnet->z->avail_out = sizeof(deflate_buffer);
     238              :                 }
     239              : 
     240              :                 /* do not continue with remaining code */
     241              :                 return;
     242              :         }
     243              : #endif /* defined(HAVE_ZLIB) */
     244              : 
     245            0 :         ev.type = TELNET_EV_SEND;
     246            0 :         ev.data.buffer = buffer;
     247            0 :         ev.data.size = size;
     248            0 :         telnet->eh(telnet, &ev, telnet->ud);
     249            0 : }
     250              : 
     251              : /* to send bags of unsigned chars */
     252              : #define _sendu(t, d, s) _send((t), (const char*)(d), (s))
     253              : 
     254              : /* check if we support a particular telopt; if us is non-zero, we
     255              :  * check if we (local) supports it, otherwise we check if he (remote)
     256              :  * supports it.  return non-zero if supported, zero if not supported.
     257              :  */
     258            0 : static INLINE int _check_telopt(telnet_t *telnet, unsigned char telopt,
     259              :                 int us) {
     260              :         int i;
     261              : 
     262              :         /* if we have no telopts table, we obviously don't support it */
     263            0 :         if (telnet->telopts == 0)
     264            0 :                 return 0;
     265              : 
     266              :         /* loop unti found or end marker (us and him both 0) */
     267            0 :         for (i = 0; telnet->telopts[i].telopt != -1; ++i) {
     268            0 :                 if (telnet->telopts[i].telopt == telopt) {
     269            0 :                         if (us && telnet->telopts[i].us == TELNET_WILL)
     270            0 :                                 return 1;
     271            0 :                         else if (!us && telnet->telopts[i].him == TELNET_DO)
     272            0 :                                 return 1;
     273              :                         else
     274            0 :                                 return 0;
     275              :                 }
     276              :         }
     277              : 
     278              :         /* not found, so not supported */
     279            0 :         return 0;
     280              : }
     281              : 
     282              : /* retrieve RFC1143 option state */
     283            0 : static INLINE telnet_rfc1143_t _get_rfc1143(telnet_t *telnet,
     284              :                 unsigned char telopt) {
     285              :         telnet_rfc1143_t empty;
     286              :         int i;
     287              : 
     288              :         /* search for entry */
     289            0 :         for (i = 0; i != telnet->q_size; ++i) {
     290            0 :                 if (telnet->q[i].telopt == telopt) {
     291            0 :                         return telnet->q[i];
     292              :                 }
     293              :         }
     294              : 
     295              :         /* not found, return empty value */
     296            0 :         empty.telopt = telopt;
     297            0 :         empty.state = 0;
     298            0 :         return empty;
     299              : }
     300              : 
     301              : /* save RFC1143 option state */
     302            0 : static INLINE void _set_rfc1143(telnet_t *telnet, unsigned char telopt,
     303              :                 char us, char him) {
     304              :         telnet_rfc1143_t *qtmp;
     305              :         int i;
     306              : 
     307              :         /* search for entry */
     308            0 :         for (i = 0; i != telnet->q_size; ++i) {
     309            0 :                 if (telnet->q[i].telopt == telopt) {
     310            0 :                         telnet->q[i].state = Q_MAKE(us,him);
     311            0 :                         if (telopt != TELNET_TELOPT_BINARY)
     312            0 :                                 return;
     313            0 :                         telnet->flags &= ~(TELNET_FLAG_TRANSMIT_BINARY |
     314              :                                            TELNET_FLAG_RECEIVE_BINARY);
     315            0 :                         if (us == Q_YES)
     316            0 :                                 telnet->flags |= TELNET_FLAG_TRANSMIT_BINARY;
     317            0 :                         if (him == Q_YES)
     318            0 :                                 telnet->flags |= TELNET_FLAG_RECEIVE_BINARY;
     319            0 :                         return;
     320              :                 }
     321              :         }
     322              : 
     323              :         /* we're going to need to track state for it, so grow the queue
     324              :          * by 4 (four) elements and put the telopt into it; bail on allocation
     325              :          * error.  we go by four because it seems like a reasonable guess as
     326              :          * to the number of enabled options for most simple code, and it
     327              :          * allows for an acceptable number of reallocations for complex code.
     328              :          */
     329            0 :         if ((qtmp = (telnet_rfc1143_t *)realloc(telnet->q,
     330            0 :                         sizeof(telnet_rfc1143_t) * (telnet->q_size + 4))) == 0) {
     331            0 :                 _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
     332            0 :                                 "realloc() failed: %s", strerror(errno));
     333            0 :                 return;
     334              :         }
     335            0 :         memset(&qtmp[telnet->q_size], 0, sizeof(telnet_rfc1143_t) * 4);
     336            0 :         telnet->q = qtmp;
     337            0 :         telnet->q[telnet->q_size].telopt = telopt;
     338            0 :         telnet->q[telnet->q_size].state = Q_MAKE(us, him);
     339            0 :         telnet->q_size += 4;
     340              : }
     341              : 
     342              : /* send negotiation bytes */
     343            0 : static INLINE void _send_negotiate(telnet_t *telnet, unsigned char cmd,
     344              :                 unsigned char telopt) {
     345              :         unsigned char bytes[3];
     346            0 :         bytes[0] = TELNET_IAC;
     347            0 :         bytes[1] = cmd;
     348            0 :         bytes[2] = telopt;
     349            0 :         _sendu(telnet, bytes, 3);
     350            0 : }
     351              : 
     352              : /* negotiation handling magic for RFC1143 */
     353            0 : static void _negotiate(telnet_t *telnet, unsigned char telopt) {
     354              :         telnet_event_t ev;
     355              :         telnet_rfc1143_t q;
     356              : 
     357              :         /* in PROXY mode, just pass it thru and do nothing */
     358            0 :         if (telnet->flags & TELNET_FLAG_PROXY) {
     359            0 :                 switch ((int)telnet->state) {
     360            0 :                 case TELNET_STATE_WILL:
     361            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
     362            0 :                         break;
     363            0 :                 case TELNET_STATE_WONT:
     364            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
     365            0 :                         break;
     366            0 :                 case TELNET_STATE_DO:
     367            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
     368            0 :                         break;
     369            0 :                 case TELNET_STATE_DONT:
     370            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
     371            0 :                         break;
     372              :                 }
     373            0 :                 return;
     374              :         }
     375              : 
     376              :         /* lookup the current state of the option */
     377            0 :         q = _get_rfc1143(telnet, telopt);
     378              : 
     379              :         /* start processing... */
     380            0 :         switch ((int)telnet->state) {
     381              :         /* request to enable option on remote end or confirm DO */
     382            0 :         case TELNET_STATE_WILL:
     383            0 :                 switch (Q_HIM(q)) {
     384            0 :                 case Q_NO:
     385            0 :                         if (_check_telopt(telnet, telopt, 0)) {
     386            0 :                                 _set_rfc1143(telnet, telopt, Q_US(q), Q_YES);
     387            0 :                                 _send_negotiate(telnet, TELNET_DO, telopt);
     388            0 :                                 NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
     389              :                         } else
     390            0 :                                 _send_negotiate(telnet, TELNET_DONT, telopt);
     391            0 :                         break;
     392            0 :                 case Q_WANTNO:
     393            0 :                         _set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
     394            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
     395            0 :                         _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
     396              :                                         "DONT answered by WILL");
     397            0 :                         break;
     398            0 :                 case Q_WANTNO_OP:
     399            0 :                         _set_rfc1143(telnet, telopt, Q_US(q), Q_YES);
     400            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
     401            0 :                         _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
     402              :                                         "DONT answered by WILL");
     403            0 :                         break;
     404            0 :                 case Q_WANTYES:
     405            0 :                         _set_rfc1143(telnet, telopt, Q_US(q), Q_YES);
     406            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
     407            0 :                         break;
     408            0 :                 case Q_WANTYES_OP:
     409            0 :                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO);
     410            0 :                         _send_negotiate(telnet, TELNET_DONT, telopt);
     411            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
     412            0 :                         break;
     413              :                 }
     414            0 :                 break;
     415              : 
     416              :         /* request to disable option on remote end, confirm DONT, reject DO */
     417            0 :         case TELNET_STATE_WONT:
     418            0 :                 switch (Q_HIM(q)) {
     419            0 :                 case Q_YES:
     420            0 :                         _set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
     421            0 :                         _send_negotiate(telnet, TELNET_DONT, telopt);
     422            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
     423            0 :                         break;
     424            0 :                 case Q_WANTNO:
     425            0 :                         _set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
     426            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
     427            0 :                         break;
     428            0 :                 case Q_WANTNO_OP:
     429            0 :                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES);
     430            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
     431            0 :                         break;
     432            0 :                 case Q_WANTYES:
     433              :                 case Q_WANTYES_OP:
     434            0 :                         _set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
     435            0 :                         break;
     436              :                 }
     437            0 :                 break;
     438              : 
     439              :         /* request to enable option on local end or confirm WILL */
     440            0 :         case TELNET_STATE_DO:
     441            0 :                 switch (Q_US(q)) {
     442            0 :                 case Q_NO:
     443            0 :                         if (_check_telopt(telnet, telopt, 1)) {
     444            0 :                                 _set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q));
     445            0 :                                 _send_negotiate(telnet, TELNET_WILL, telopt);
     446            0 :                                 NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
     447              :                         } else
     448            0 :                                 _send_negotiate(telnet, TELNET_WONT, telopt);
     449            0 :                         break;
     450            0 :                 case Q_WANTNO:
     451            0 :                         _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
     452            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
     453            0 :                         _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
     454              :                                         "WONT answered by DO");
     455            0 :                         break;
     456            0 :                 case Q_WANTNO_OP:
     457            0 :                         _set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q));
     458            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
     459            0 :                         _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
     460              :                                         "WONT answered by DO");
     461            0 :                         break;
     462            0 :                 case Q_WANTYES:
     463            0 :                         _set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q));
     464            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
     465            0 :                         break;
     466            0 :                 case Q_WANTYES_OP:
     467            0 :                         _set_rfc1143(telnet, telopt, Q_WANTNO, Q_HIM(q));
     468            0 :                         _send_negotiate(telnet, TELNET_WONT, telopt);
     469            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
     470            0 :                         break;
     471              :                 }
     472            0 :                 break;
     473              : 
     474              :         /* request to disable option on local end, confirm WONT, reject WILL */
     475            0 :         case TELNET_STATE_DONT:
     476            0 :                 switch (Q_US(q)) {
     477            0 :                 case Q_YES:
     478            0 :                         _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
     479            0 :                         _send_negotiate(telnet, TELNET_WONT, telopt);
     480            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
     481            0 :                         break;
     482            0 :                 case Q_WANTNO:
     483            0 :                         _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
     484            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
     485            0 :                         break;
     486            0 :                 case Q_WANTNO_OP:
     487            0 :                         _set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q));
     488            0 :                         _send_negotiate(telnet, TELNET_WILL, telopt);
     489            0 :                         NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
     490            0 :                         break;
     491            0 :                 case Q_WANTYES:
     492              :                 case Q_WANTYES_OP:
     493            0 :                         _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
     494            0 :                         break;
     495              :                 }
     496            0 :                 break;
     497              :         }
     498              : }
     499              : 
     500              : /* process an ENVIRON/NEW-ENVIRON subnegotiation buffer
     501              :  *
     502              :  * the algorithm and approach used here is kind of a hack,
     503              :  * but it reduces the number of memory allocations we have
     504              :  * to make.
     505              :  *
     506              :  * we copy the bytes back into the buffer, starting at the very
     507              :  * beginning, which makes it easy to handle the ENVIRON ESC
     508              :  * escape mechanism as well as ensure the variable name and
     509              :  * value strings are NUL-terminated, all while fitting inside
     510              :  * of the original buffer.
     511              :  */
     512            0 : static int _environ_telnet(telnet_t *telnet, unsigned char type,
     513              :                 char* buffer, size_t size) {
     514              :         telnet_event_t ev;
     515            0 :         struct telnet_environ_t *values = 0;
     516              :         char *c, *last, *out;
     517              :         size_t index, count;
     518              : 
     519              :         /* if we have no data, just pass it through */
     520            0 :         if (size == 0) {
     521            0 :                 return 0;
     522              :         }
     523              : 
     524              :         /* first byte must be a valid command */
     525            0 :         if ((unsigned)buffer[0] != TELNET_ENVIRON_SEND &&
     526            0 :                         (unsigned)buffer[0] != TELNET_ENVIRON_IS &&
     527            0 :                         (unsigned)buffer[0] != TELNET_ENVIRON_INFO) {
     528            0 :                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
     529              :                                 "telopt %d subneg has invalid command", type);
     530            0 :                 return 0;
     531              :         }
     532              : 
     533              :         /* store ENVIRON command */
     534            0 :         ev.environ.cmd = buffer[0];
     535              : 
     536              :         /* if we have no arguments, send an event with no data end return */
     537            0 :         if (size == 1) {
     538              :                 /* no list of variables given */
     539            0 :                 ev.environ.values = 0;
     540            0 :                 ev.environ.size = 0;
     541              : 
     542              :                 /* invoke event with our arguments */
     543            0 :                 ev.type = TELNET_EV_ENVIRON;
     544            0 :                 telnet->eh(telnet, &ev, telnet->ud);
     545              : 
     546            0 :                 return 1;
     547              :         }
     548              : 
     549              :         /* very second byte must be VAR or USERVAR, if present */
     550            0 :         if ((unsigned)buffer[1] != TELNET_ENVIRON_VAR &&
     551            0 :                         (unsigned)buffer[1] != TELNET_ENVIRON_USERVAR) {
     552            0 :                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
     553              :                                 "telopt %d subneg missing variable type", type);
     554            0 :                 return 0;
     555              :         }
     556              : 
     557              :         /* ensure last byte is not an escape byte (makes parsing later easier) */
     558            0 :         if ((unsigned)buffer[size - 1] == TELNET_ENVIRON_ESC) {
     559            0 :                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
     560              :                                 "telopt %d subneg ends with ESC", type);
     561            0 :                 return 0;
     562              :         }
     563              : 
     564              :         /* count arguments; each valid entry starts with VAR or USERVAR */
     565            0 :         count = 0;
     566            0 :         for (c = buffer + 1; c < buffer + size; ++c) {
     567            0 :                 if (*c == TELNET_ENVIRON_VAR || *c == TELNET_ENVIRON_USERVAR) {
     568            0 :                         ++count;
     569            0 :                 } else if (*c == TELNET_ENVIRON_ESC) {
     570              :                         /* skip the next byte */
     571            0 :                         ++c;
     572              :                 }
     573              :         }
     574              : 
     575              :         /* allocate argument array, bail on error */
     576            0 :         if ((values = (struct telnet_environ_t *)calloc(count,
     577              :                         sizeof(struct telnet_environ_t))) == 0) {
     578            0 :                 _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
     579            0 :                                 "calloc() failed: %s", strerror(errno));
     580            0 :                 return 0;
     581              :         }
     582              : 
     583              :         /* parse argument array strings */
     584            0 :         out = buffer;
     585            0 :         c = buffer + 1;
     586            0 :         for (index = 0; index != count; ++index) {
     587              :                 /* remember the variable type (will be VAR or USERVAR) */
     588            0 :                 values[index].type = *c++;
     589              : 
     590              :                 /* scan until we find an end-marker, and buffer up unescaped
     591              :                  * bytes into our buffer */
     592            0 :                 last = out;
     593            0 :                 while (c < buffer + size) {
     594              :                         /* stop at the next variable or at the value */
     595            0 :                         if ((unsigned)*c == TELNET_ENVIRON_VAR ||
     596            0 :                                         (unsigned)*c == TELNET_ENVIRON_VALUE ||
     597            0 :                                         (unsigned)*c == TELNET_ENVIRON_USERVAR) {
     598              :                                 break;
     599              :                         }
     600              : 
     601              :                         /* buffer next byte (taking into account ESC) */
     602            0 :                         if (*c == TELNET_ENVIRON_ESC) {
     603            0 :                                 ++c;
     604              :                         }
     605              : 
     606            0 :                         *out++ = *c++;
     607              :                 }
     608            0 :                 *out++ = '\0';
     609              : 
     610              :                 /* store the variable name we have just received */
     611            0 :                 values[index].var = last;
     612            0 :                 values[index].value = "";
     613              : 
     614              :                 /* if we got a value, find the next end marker and
     615              :                  * store the value; otherwise, store empty string */
     616            0 :                 if (c < buffer + size && *c == TELNET_ENVIRON_VALUE) {
     617            0 :                         ++c;
     618            0 :                         last = out;
     619            0 :                         while (c < buffer + size) {
     620              :                                 /* stop when we find the start of the next variable */
     621            0 :                                 if ((unsigned)*c == TELNET_ENVIRON_VAR ||
     622            0 :                                                 (unsigned)*c == TELNET_ENVIRON_USERVAR) {
     623              :                                         break;
     624              :                                 }
     625              : 
     626              :                                 /* buffer next byte (taking into account ESC) */
     627            0 :                                 if (*c == TELNET_ENVIRON_ESC) {
     628            0 :                                         ++c;
     629              :                                 }
     630              : 
     631            0 :                                 *out++ = *c++;
     632              :                         }
     633            0 :                         *out++ = '\0';
     634              : 
     635              :                         /* store the variable value */
     636            0 :                         values[index].value = last;
     637              :                 }
     638              :         }
     639              : 
     640              :         /* pass values array and count to event */
     641            0 :         ev.environ.values = values;
     642            0 :         ev.environ.size = count;
     643              : 
     644              :         /* invoke event with our arguments */
     645            0 :         ev.type = TELNET_EV_ENVIRON;
     646            0 :         telnet->eh(telnet, &ev, telnet->ud);
     647              : 
     648              :         /* clean up */
     649            0 :         free(values);
     650            0 :         return 1;
     651              : }
     652              : 
     653              : /* process an MSSP subnegotiation buffer */
     654            0 : static int _mssp_telnet(telnet_t *telnet, char* buffer, size_t size) {
     655              :         telnet_event_t ev;
     656              :         struct telnet_environ_t *values;
     657            0 :         char *var = 0;
     658              :         char *c, *last, *out;
     659              :         size_t i, count;
     660              :         unsigned char next_type;
     661              : 
     662              :         /* if we have no data, just pass it through */
     663            0 :         if (size == 0) {
     664            0 :                 return 0;
     665              :         }
     666              : 
     667              :         /* first byte must be a VAR */
     668            0 :         if ((unsigned)buffer[0] != TELNET_MSSP_VAR) {
     669            0 :                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
     670              :                                 "MSSP subnegotiation has invalid data");
     671            0 :                 return 0;
     672              :         }
     673              : 
     674              :         /* count the arguments, any part that starts with VALUE */
     675            0 :         for (count = 0, i = 0; i != size; ++i) {
     676            0 :                 if ((unsigned)buffer[i] == TELNET_MSSP_VAL) {
     677            0 :                         ++count;
     678              :                 }
     679              :         }
     680              : 
     681              :         /* allocate argument array, bail on error */
     682            0 :         if ((values = (struct telnet_environ_t *)calloc(count,
     683              :                         sizeof(struct telnet_environ_t))) == 0) {
     684            0 :                 _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
     685            0 :                                 "calloc() failed: %s", strerror(errno));
     686            0 :                 return 0;
     687              :         }
     688              : 
     689            0 :         ev.mssp.values = values;
     690            0 :         ev.mssp.size = count;
     691              : 
     692              :         /* allocate strings in argument array */
     693            0 :         out = last = buffer;
     694            0 :         next_type = buffer[0];
     695            0 :         for (i = 0, c = buffer + 1; c < buffer + size;) {
     696              :                 /* search for end marker */
     697            0 :                 while (c < buffer + size && (unsigned)*c != TELNET_MSSP_VAR &&
     698            0 :                                 (unsigned)*c != TELNET_MSSP_VAL) {
     699            0 :                         *out++ = *c++;
     700              :                 }
     701            0 :                 *out++ = '\0';
     702              : 
     703              :                 /* if it's a variable name, just store the name for now */
     704            0 :                 if (next_type == TELNET_MSSP_VAR) {
     705            0 :                         var = last;
     706            0 :                 } else if (next_type == TELNET_MSSP_VAL && var != 0) {
     707            0 :                         values[i].var = var;
     708            0 :                         values[i].value = last;
     709            0 :                         ++i;
     710              :                 } else {
     711            0 :                         _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
     712              :                                         "invalid MSSP subnegotiation data");
     713            0 :                         free(values);
     714            0 :                         return 0;
     715              :                 }
     716              : 
     717              :                 /* remember our next type and increment c for next loop run */
     718            0 :                 last = out;
     719            0 :                 next_type = *c++;
     720              :         }
     721              : 
     722              :         /* invoke event with our arguments */
     723            0 :         ev.type = TELNET_EV_MSSP;
     724            0 :         telnet->eh(telnet, &ev, telnet->ud);
     725              : 
     726              :         /* clean up */
     727            0 :         free(values);
     728              : 
     729            0 :         return 0;
     730              : }
     731              : 
     732              : /* parse ZMP command subnegotiation buffers */
     733            0 : static int _zmp_telnet(telnet_t *telnet, const char* buffer, size_t size) {
     734              :         telnet_event_t ev;
     735              :         char **argv;
     736              :         const char *c;
     737              :         size_t i, argc;
     738              : 
     739              :         /* make sure this is a valid ZMP buffer */
     740            0 :         if (size == 0 || buffer[size - 1] != 0) {
     741            0 :                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
     742              :                                 "incomplete ZMP frame");
     743            0 :                 return 0;
     744              :         }
     745              : 
     746              :         /* count arguments */
     747            0 :         for (argc = 0, c = buffer; c != buffer + size; ++argc)
     748            0 :                 c += strlen(c) + 1;
     749              : 
     750              :         /* allocate argument array, bail on error */
     751            0 :         if ((argv = (char **)calloc(argc, sizeof(char *))) == 0) {
     752            0 :                 _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
     753            0 :                                 "calloc() failed: %s", strerror(errno));
     754            0 :                 return 0;
     755              :         }
     756              : 
     757              :         /* populate argument array */
     758            0 :         for (i = 0, c = buffer; i != argc; ++i) {
     759            0 :                 argv[i] = (char *)c;
     760            0 :                 c += strlen(c) + 1;
     761              :         }
     762              : 
     763              :         /* invoke event with our arguments */
     764            0 :         ev.type = TELNET_EV_ZMP;
     765            0 :         ev.zmp.argv = (const char**)argv;
     766            0 :         ev.zmp.argc = argc;
     767            0 :         telnet->eh(telnet, &ev, telnet->ud);
     768              : 
     769              :         /* clean up */
     770            0 :         free(argv);
     771            0 :         return 0;
     772              : }
     773              : 
     774              : /* parse TERMINAL-TYPE command subnegotiation buffers */
     775            0 : static int _ttype_telnet(telnet_t *telnet, const char* buffer, size_t size) {
     776              :         telnet_event_t ev;
     777              : 
     778              :         /* make sure request is not empty */
     779            0 :         if (size == 0) {
     780            0 :                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
     781              :                                 "incomplete TERMINAL-TYPE request");
     782            0 :                 return 0;
     783              :         }
     784              : 
     785              :         /* make sure request has valid command type */
     786            0 :         if (buffer[0] != TELNET_TTYPE_IS &&
     787            0 :                         buffer[0] != TELNET_TTYPE_SEND) {
     788            0 :                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
     789              :                                 "TERMINAL-TYPE request has invalid type");
     790            0 :                 return 0;
     791              :         }
     792              : 
     793              :         /* send proper event */
     794            0 :         if (buffer[0] == TELNET_TTYPE_IS) {
     795              :                 char *name;
     796              : 
     797              :                 /* allocate space for name */
     798            0 :                 if ((name = (char *)malloc(size)) == 0) {
     799            0 :                         _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
     800            0 :                                         "malloc() failed: %s", strerror(errno));
     801            0 :                         return 0;
     802              :                 }
     803            0 :                 memcpy(name, buffer + 1, size - 1);
     804            0 :                 name[size - 1] = '\0';
     805              : 
     806            0 :                 ev.type = TELNET_EV_TTYPE;
     807            0 :                 ev.ttype.cmd = TELNET_TTYPE_IS;
     808            0 :                 ev.ttype.name = name;
     809            0 :                 telnet->eh(telnet, &ev, telnet->ud);
     810              : 
     811              :                 /* clean up */
     812            0 :                 free(name);
     813              :         } else {
     814            0 :                 ev.type = TELNET_EV_TTYPE;
     815            0 :                 ev.ttype.cmd = TELNET_TTYPE_SEND;
     816            0 :                 ev.ttype.name = 0;
     817            0 :                 telnet->eh(telnet, &ev, telnet->ud);
     818              :         }
     819              : 
     820            0 :         return 0;
     821              : }
     822              : 
     823              : /* process a subnegotiation buffer; return non-zero if the current buffer
     824              :  * must be aborted and reprocessed due to COMPRESS2 being activated
     825              :  */
     826            0 : static int _subnegotiate(telnet_t *telnet) {
     827              :         telnet_event_t ev;
     828              : 
     829              :         /* standard subnegotiation event */
     830            0 :         ev.type = TELNET_EV_SUBNEGOTIATION;
     831            0 :         ev.sub.telopt = telnet->sb_telopt;
     832            0 :         ev.sub.buffer = telnet->buffer;
     833            0 :         ev.sub.size = telnet->buffer_pos;
     834            0 :         telnet->eh(telnet, &ev, telnet->ud);
     835              : 
     836            0 :         switch (telnet->sb_telopt) {
     837              : #if defined(HAVE_ZLIB)
     838              :         /* received COMPRESS2 begin marker, setup our zlib box and
     839              :          * start handling the compressed stream if it's not already.
     840              :          */
     841              :         case TELNET_TELOPT_COMPRESS2:
     842              :                 if (telnet->sb_telopt == TELNET_TELOPT_COMPRESS2) {
     843              :                         if (_init_zlib(telnet, 0, 1) != TELNET_EOK)
     844              :                                 return 0;
     845              : 
     846              :                         /* notify app that compression was enabled */
     847              :                         ev.type = TELNET_EV_COMPRESS;
     848              :                         ev.compress.state = 1;
     849              :                         telnet->eh(telnet, &ev, telnet->ud);
     850              :                         return 1;
     851              :                 }
     852              :                 return 0;
     853              : #endif /* defined(HAVE_ZLIB) */
     854              : 
     855              :         /* specially handled subnegotiation telopt types */
     856            0 :         case TELNET_TELOPT_ZMP:
     857            0 :                 return _zmp_telnet(telnet, telnet->buffer, telnet->buffer_pos);
     858            0 :         case TELNET_TELOPT_TTYPE:
     859            0 :                 return _ttype_telnet(telnet, telnet->buffer, telnet->buffer_pos);
     860            0 :         case TELNET_TELOPT_ENVIRON:
     861              :         case TELNET_TELOPT_NEW_ENVIRON:
     862            0 :                 return _environ_telnet(telnet, telnet->sb_telopt, telnet->buffer,
     863              :                                 telnet->buffer_pos);
     864            0 :         case TELNET_TELOPT_MSSP:
     865            0 :                 return _mssp_telnet(telnet, telnet->buffer, telnet->buffer_pos);
     866            0 :         default:
     867            0 :                 return 0;
     868              :         }
     869              : }
     870              : 
     871              : /* initialize a telnet state tracker */
     872            0 : telnet_t *telnet_init(const telnet_telopt_t *telopts,
     873              :                 telnet_event_handler_t eh, unsigned char flags, void *user_data) {
     874              :         /* allocate structure */
     875            0 :         struct telnet_t *telnet = (telnet_t*)calloc(1, sizeof(telnet_t));
     876            0 :         if (telnet == 0)
     877            0 :                 return 0;
     878              : 
     879              :         /* initialize data */
     880            0 :         telnet->ud = user_data;
     881            0 :         telnet->telopts = telopts;
     882            0 :         telnet->eh = eh;
     883            0 :         telnet->flags = flags;
     884              : 
     885            0 :         return telnet;
     886              : }
     887              : 
     888              : /* free up any memory allocated by a state tracker */
     889            0 : void telnet_free(telnet_t *telnet) {
     890              :         /* free sub-request buffer */
     891            0 :         if (telnet->buffer != 0) {
     892            0 :                 free(telnet->buffer);
     893            0 :                 telnet->buffer = 0;
     894            0 :                 telnet->buffer_size = 0;
     895            0 :                 telnet->buffer_pos = 0;
     896              :         }
     897              : 
     898              : #if defined(HAVE_ZLIB)
     899              :         /* free zlib box */
     900              :         if (telnet->z != 0) {
     901              :                 if (telnet->flags & TELNET_PFLAG_DEFLATE)
     902              :                         deflateEnd(telnet->z);
     903              :                 else
     904              :                         inflateEnd(telnet->z);
     905              :                 free(telnet->z);
     906              :                 telnet->z = 0;
     907              :         }
     908              : #endif /* defined(HAVE_ZLIB) */
     909              : 
     910              :         /* free RFC1143 queue */
     911            0 :         if (telnet->q) {
     912            0 :                 free(telnet->q);
     913            0 :                 telnet->q = 0;
     914            0 :                 telnet->q_size = 0;
     915              :         }
     916              : 
     917              :         /* free the telnet structure itself */
     918            0 :         free(telnet);
     919            0 : }
     920              : 
     921              : /* push a byte into the telnet buffer */
     922            0 : static telnet_error_t _buffer_byte(telnet_t *telnet,
     923              :                 unsigned char byte) {
     924              :         char *new_buffer;
     925              : 
     926              : 
     927              :         /* check if we're out of room */
     928            0 :         if (telnet->buffer_pos == telnet->buffer_size) {
     929              :        size_t i;
     930              :                 /* find the next buffer size */
     931            0 :                 for (i = 0; i != _buffer_sizes_count; ++i) {
     932            0 :                         if (_buffer_sizes[i] == telnet->buffer_size) {
     933            0 :                                 break;
     934              :                         }
     935              :                 }
     936              : 
     937              :                 /* overflow -- can't grow any more */
     938            0 :                 if (i >= _buffer_sizes_count - 1) {
     939            0 :                         _error(telnet, __LINE__, __func__, TELNET_EOVERFLOW, 0,
     940              :                                         "subnegotiation buffer size limit reached");
     941            0 :                         return TELNET_EOVERFLOW;
     942              :                 }
     943              : 
     944              :                 /* (re)allocate buffer */
     945            0 :                 new_buffer = (char *)realloc(telnet->buffer, _buffer_sizes[i + 1]);
     946            0 :                 if (new_buffer == 0) {
     947            0 :                         _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
     948              :                                         "realloc() failed");
     949            0 :                         return TELNET_ENOMEM;
     950              :                 }
     951              : 
     952            0 :                 telnet->buffer = new_buffer;
     953            0 :                 telnet->buffer_size = _buffer_sizes[i + 1];
     954              :         }
     955              : 
     956              :         /* push the byte, all set */
     957            0 :         telnet->buffer[telnet->buffer_pos++] = byte;
     958            0 :         return TELNET_EOK;
     959              : }
     960              : 
     961            0 : static void _process(telnet_t *telnet, const char *buffer, size_t size) {
     962              :         telnet_event_t ev;
     963              :         unsigned char byte;
     964              :         size_t i, start;
     965            0 :         for (i = start = 0; i != size; ++i) {
     966            0 :                 byte = buffer[i];
     967            0 :                 switch (telnet->state) {
     968              :                 /* regular data */
     969            0 :                 case TELNET_STATE_DATA:
     970              :                         /* on an IAC byte, pass through all pending bytes and
     971              :                          * switch states */
     972            0 :                         if (byte == TELNET_IAC) {
     973            0 :                                 if (i != start) {
     974            0 :                                         ev.type = TELNET_EV_DATA;
     975            0 :                                         ev.data.buffer = buffer + start;
     976            0 :                                         ev.data.size = i - start;
     977            0 :                                         telnet->eh(telnet, &ev, telnet->ud);
     978              :                                 }
     979            0 :                                 telnet->state = TELNET_STATE_IAC;
     980            0 :                         } else if (byte == '\r' &&
     981            0 :                                            (telnet->flags & TELNET_FLAG_NVT_EOL) &&
     982            0 :                                            !(telnet->flags & TELNET_FLAG_RECEIVE_BINARY)) {
     983            0 :                                 if (i != start) {
     984            0 :                                         ev.type = TELNET_EV_DATA;
     985            0 :                                         ev.data.buffer = buffer + start;
     986            0 :                                         ev.data.size = i - start;
     987            0 :                                         telnet->eh(telnet, &ev, telnet->ud);
     988              :                                 }
     989            0 :                                 telnet->state = TELNET_STATE_EOL;
     990              :                         }
     991            0 :                         break;
     992              : 
     993              :                 /* NVT EOL to be translated */
     994            0 :                 case TELNET_STATE_EOL:
     995            0 :                         if (byte != '\n') {
     996            0 :                                 byte = '\r';
     997            0 :                                 ev.type = TELNET_EV_DATA;
     998            0 :                                 ev.data.buffer = (char*)&byte;
     999            0 :                                 ev.data.size = 1;
    1000            0 :                                 telnet->eh(telnet, &ev, telnet->ud);
    1001            0 :                                 byte = buffer[i];
    1002              :                         }
    1003              :                         // any byte following '\r' other than '\n' or '\0' is invalid,
    1004              :                         // so pass both \r and the byte
    1005            0 :                         start = i;
    1006            0 :                         if (byte == '\0')
    1007            0 :                                 ++start;
    1008              :                         /* state update */
    1009            0 :                         telnet->state = TELNET_STATE_DATA;
    1010            0 :                         break;
    1011              : 
    1012              :                 /* IAC command */
    1013            0 :                 case TELNET_STATE_IAC:
    1014            0 :                         switch (byte) {
    1015              :                         /* subnegotiation */
    1016            0 :                         case TELNET_SB:
    1017            0 :                                 telnet->state = TELNET_STATE_SB;
    1018            0 :                                 break;
    1019              :                         /* negotiation commands */
    1020            0 :                         case TELNET_WILL:
    1021            0 :                                 telnet->state = TELNET_STATE_WILL;
    1022            0 :                                 break;
    1023            0 :                         case TELNET_WONT:
    1024            0 :                                 telnet->state = TELNET_STATE_WONT;
    1025            0 :                                 break;
    1026            0 :                         case TELNET_DO:
    1027            0 :                                 telnet->state = TELNET_STATE_DO;
    1028            0 :                                 break;
    1029            0 :                         case TELNET_DONT:
    1030            0 :                                 telnet->state = TELNET_STATE_DONT;
    1031            0 :                                 break;
    1032              :                         /* IAC escaping */
    1033            0 :                         case TELNET_IAC:
    1034              :                                 /* event */
    1035            0 :                                 ev.type = TELNET_EV_DATA;
    1036            0 :                                 ev.data.buffer = (char*)&byte;
    1037            0 :                                 ev.data.size = 1;
    1038            0 :                                 telnet->eh(telnet, &ev, telnet->ud);
    1039              : 
    1040              :                                 /* state update */
    1041            0 :                                 start = i + 1;
    1042            0 :                                 telnet->state = TELNET_STATE_DATA;
    1043            0 :                                 break;
    1044              :                         /* some other command */
    1045            0 :                         default:
    1046              :                                 /* event */
    1047            0 :                                 ev.type = TELNET_EV_IAC;
    1048            0 :                                 ev.iac.cmd = byte;
    1049            0 :                                 telnet->eh(telnet, &ev, telnet->ud);
    1050              : 
    1051              :                                 /* state update */
    1052            0 :                                 start = i + 1;
    1053            0 :                                 telnet->state = TELNET_STATE_DATA;
    1054              :                         }
    1055            0 :                         break;
    1056              : 
    1057              :                 /* negotiation commands */
    1058            0 :                 case TELNET_STATE_WILL:
    1059              :                 case TELNET_STATE_WONT:
    1060              :                 case TELNET_STATE_DO:
    1061              :                 case TELNET_STATE_DONT:
    1062            0 :                         _negotiate(telnet, byte);
    1063            0 :                         start = i + 1;
    1064            0 :                         telnet->state = TELNET_STATE_DATA;
    1065            0 :                         break;
    1066              : 
    1067              :                 /* subnegotiation -- determine subnegotiation telopt */
    1068            0 :                 case TELNET_STATE_SB:
    1069            0 :                         telnet->sb_telopt = byte;
    1070            0 :                         telnet->buffer_pos = 0;
    1071            0 :                         telnet->state = TELNET_STATE_SB_DATA;
    1072            0 :                         break;
    1073              : 
    1074              :                 /* subnegotiation -- buffer bytes until end request */
    1075            0 :                 case TELNET_STATE_SB_DATA:
    1076              :                         /* IAC command in subnegotiation -- either IAC SE or IAC IAC */
    1077            0 :                         if (byte == TELNET_IAC) {
    1078            0 :                                 telnet->state = TELNET_STATE_SB_DATA_IAC;
    1079            0 :                         } else if (telnet->sb_telopt == TELNET_TELOPT_COMPRESS && byte == TELNET_WILL) {
    1080              :                                 /* In 1998 MCCP used TELOPT 85 and the protocol defined an invalid
    1081              :                                  * subnegotiation sequence (IAC SB 85 WILL SE) to start compression.
    1082              :                                  * Subsequently MCCP version 2 was created in 2000 using TELOPT 86
    1083              :                                  * and a valid subnegotiation (IAC SB 86 IAC SE). libtelnet for now
    1084              :                                  * just captures and discards MCCPv1 sequences.
    1085              :                                  */
    1086            0 :                                 start = i + 2;
    1087            0 :                                 telnet->state = TELNET_STATE_DATA;
    1088              :                         /* buffer the byte, or bail if we can't */
    1089            0 :                         } else if (_buffer_byte(telnet, byte) != TELNET_EOK) {
    1090            0 :                                 start = i + 1;
    1091            0 :                                 telnet->state = TELNET_STATE_DATA;
    1092              :                         }
    1093            0 :                         break;
    1094              : 
    1095              :                 /* IAC escaping inside a subnegotiation */
    1096            0 :                 case TELNET_STATE_SB_DATA_IAC:
    1097            0 :                         switch (byte) {
    1098              :                         /* end subnegotiation */
    1099            0 :                         case TELNET_SE:
    1100              :                                 /* return to default state */
    1101            0 :                                 start = i + 1;
    1102            0 :                                 telnet->state = TELNET_STATE_DATA;
    1103              : 
    1104              :                                 /* process subnegotiation */
    1105            0 :                                 if (_subnegotiate(telnet) != 0) {
    1106              :                                         /* any remaining bytes in the buffer are compressed.
    1107              :                                          * we have to re-invoke telnet_recv to get those
    1108              :                                          * bytes inflated and abort trying to process the
    1109              :                                          * remaining compressed bytes in the current _process
    1110              :                                          * buffer argument
    1111              :                                          */
    1112            0 :                                         telnet_recv(telnet, &buffer[start], size - start);
    1113            0 :                                         return;
    1114              :                                 }
    1115            0 :                                 break;
    1116              :                         /* escaped IAC byte */
    1117            0 :                         case TELNET_IAC:
    1118              :                                 /* push IAC into buffer */
    1119            0 :                                 if (_buffer_byte(telnet, TELNET_IAC) !=
    1120              :                                                 TELNET_EOK) {
    1121            0 :                                         start = i + 1;
    1122            0 :                                         telnet->state = TELNET_STATE_DATA;
    1123              :                                 } else {
    1124            0 :                                         telnet->state = TELNET_STATE_SB_DATA;
    1125              :                                 }
    1126            0 :                                 break;
    1127              :                         /* something else -- protocol error.  attempt to process
    1128              :                          * content in subnegotiation buffer, then evaluate the
    1129              :                          * given command as an IAC code.
    1130              :                          */
    1131            0 :                         default:
    1132            0 :                                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
    1133              :                                                 "unexpected byte after IAC inside SB: %d",
    1134              :                                                 byte);
    1135              : 
    1136              :                                 /* enter IAC state */
    1137            0 :                                 start = i + 1;
    1138            0 :                                 telnet->state = TELNET_STATE_IAC;
    1139              : 
    1140              :                                 /* process subnegotiation; see comment in
    1141              :                                  * TELNET_STATE_SB_DATA_IAC about invoking telnet_recv()
    1142              :                                  */
    1143            0 :                                 if (_subnegotiate(telnet) != 0) {
    1144            0 :                                         telnet_recv(telnet, &buffer[start], size - start);
    1145            0 :                                         return;
    1146              :                                 } else {
    1147              :                                         /* recursive call to get the current input byte processed
    1148              :                                          * as a regular IAC command.  we could use a goto, but
    1149              :                                          * that would be gross.
    1150              :                                          */
    1151            0 :                                         _process(telnet, (char *)&byte, 1);
    1152              :                                 }
    1153            0 :                                 break;
    1154              :                         }
    1155            0 :                         break;
    1156              :                 }
    1157              :         }
    1158              : 
    1159              :         /* pass through any remaining bytes */
    1160            0 :         if (telnet->state == TELNET_STATE_DATA && i != start) {
    1161            0 :                 ev.type = TELNET_EV_DATA;
    1162            0 :                 ev.data.buffer = buffer + start;
    1163            0 :                 ev.data.size = i - start;
    1164            0 :                 telnet->eh(telnet, &ev, telnet->ud);
    1165              :         }
    1166              : }
    1167              : 
    1168              : /* push a bytes into the state tracker */
    1169            0 : void telnet_recv(telnet_t *telnet, const char *buffer,
    1170              :                 size_t size) {
    1171              : #if defined(HAVE_ZLIB)
    1172              :         /* if we have an inflate (decompression) zlib stream, use it */
    1173              :         if (telnet->z != 0 && !(telnet->flags & TELNET_PFLAG_DEFLATE)) {
    1174              :                 char inflate_buffer[1024];
    1175              : 
    1176              : 
    1177              :                 /* initialize zlib state */
    1178              :                 telnet->z->next_in = (unsigned char*)buffer;
    1179              :                 telnet->z->avail_in = (unsigned int)size;
    1180              :                 telnet->z->next_out = (unsigned char *)inflate_buffer;
    1181              :                 telnet->z->avail_out = sizeof(inflate_buffer);
    1182              : 
    1183              :                 /* inflate until buffer exhausted and all output is produced */
    1184              :                 while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) {
    1185              :                     int rs;
    1186              :            /* reset output buffer */
    1187              : 
    1188              :                         /* decompress */
    1189              :                         rs = inflate(telnet->z, Z_SYNC_FLUSH);
    1190              : 
    1191              :                         /* process the decompressed bytes on success */
    1192              :                         if (rs == Z_OK || rs == Z_STREAM_END)
    1193              :                                 _process(telnet, inflate_buffer, sizeof(inflate_buffer) -
    1194              :                                                 telnet->z->avail_out);
    1195              :                         else
    1196              :                                 _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, 1,
    1197              :                                                 "inflate() failed: %s", zError(rs));
    1198              : 
    1199              :                         /* prepare output buffer for next run */
    1200              :                         telnet->z->next_out = (unsigned char *)inflate_buffer;
    1201              :                         telnet->z->avail_out = sizeof(inflate_buffer);
    1202              : 
    1203              :                         /* on error (or on end of stream) disable further inflation */
    1204              :                         if (rs != Z_OK) {
    1205              :                                 telnet_event_t ev;
    1206              : 
    1207              :                                 /* disable compression */
    1208              :                                 inflateEnd(telnet->z);
    1209              :                                 free(telnet->z);
    1210              :                                 telnet->z = 0;
    1211              : 
    1212              :                                 /* send event */
    1213              :                                 ev.type = TELNET_EV_COMPRESS;
    1214              :                                 ev.compress.state = 0;
    1215              :                                 telnet->eh(telnet, &ev, telnet->ud);
    1216              : 
    1217              :                                 break;
    1218              :                         }
    1219              :                 }
    1220              : 
    1221              :         /* COMPRESS2 is not negotiated, just process */
    1222              :         } else
    1223              : #endif /* defined(HAVE_ZLIB) */
    1224            0 :                 _process(telnet, buffer, size);
    1225            0 : }
    1226              : 
    1227              : /* send an iac command */
    1228            0 : void telnet_iac(telnet_t *telnet, unsigned char cmd) {
    1229              :         unsigned char bytes[2];
    1230            0 :         bytes[0] = TELNET_IAC;
    1231            0 :         bytes[1] = cmd;
    1232            0 :         _sendu(telnet, bytes, 2);
    1233            0 : }
    1234              : 
    1235              : /* send negotiation */
    1236            0 : void telnet_negotiate(telnet_t *telnet, unsigned char cmd,
    1237              :                 unsigned char telopt) {
    1238              :         telnet_rfc1143_t q;
    1239              : 
    1240              :         /* if we're in proxy mode, just send it now */
    1241            0 :         if (telnet->flags & TELNET_FLAG_PROXY) {
    1242              :                 unsigned char bytes[3];
    1243            0 :                 bytes[0] = TELNET_IAC;
    1244            0 :                 bytes[1] = cmd;
    1245            0 :                 bytes[2] = telopt;
    1246            0 :                 _sendu(telnet, bytes, 3);
    1247            0 :                 return;
    1248              :         }
    1249              : 
    1250              :         /* get current option states */
    1251            0 :         q = _get_rfc1143(telnet, telopt);
    1252              : 
    1253            0 :         switch (cmd) {
    1254              :         /* advertise willingess to support an option */
    1255            0 :         case TELNET_WILL:
    1256            0 :                 switch (Q_US(q)) {
    1257            0 :                 case Q_NO:
    1258            0 :                         _set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q));
    1259            0 :                         _send_negotiate(telnet, TELNET_WILL, telopt);
    1260            0 :                         break;
    1261            0 :                 case Q_WANTNO:
    1262            0 :                         _set_rfc1143(telnet, telopt, Q_WANTNO_OP, Q_HIM(q));
    1263            0 :                         break;
    1264            0 :                 case Q_WANTYES_OP:
    1265            0 :                         _set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q));
    1266            0 :                         break;
    1267              :                 }
    1268            0 :                 break;
    1269              : 
    1270              :         /* force turn-off of locally enabled option */
    1271            0 :         case TELNET_WONT:
    1272            0 :                 switch (Q_US(q)) {
    1273            0 :                 case Q_YES:
    1274            0 :                         _set_rfc1143(telnet, telopt, Q_WANTNO, Q_HIM(q));
    1275            0 :                         _send_negotiate(telnet, TELNET_WONT, telopt);
    1276            0 :                         break;
    1277            0 :                 case Q_WANTYES:
    1278            0 :                         _set_rfc1143(telnet, telopt, Q_WANTYES_OP, Q_HIM(q));
    1279            0 :                         break;
    1280            0 :                 case Q_WANTNO_OP:
    1281            0 :                         _set_rfc1143(telnet, telopt, Q_WANTNO, Q_HIM(q));
    1282            0 :                         break;
    1283              :                 }
    1284            0 :                 break;
    1285              : 
    1286              :         /* ask remote end to enable an option */
    1287            0 :         case TELNET_DO:
    1288            0 :                 switch (Q_HIM(q)) {
    1289            0 :                 case Q_NO:
    1290            0 :                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES);
    1291            0 :                         _send_negotiate(telnet, TELNET_DO, telopt);
    1292            0 :                         break;
    1293            0 :                 case Q_WANTNO:
    1294            0 :                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO_OP);
    1295            0 :                         break;
    1296            0 :                 case Q_WANTYES_OP:
    1297            0 :                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES);
    1298            0 :                         break;
    1299              :                 }
    1300            0 :                 break;
    1301              : 
    1302              :         /* demand remote end disable an option */
    1303            0 :         case TELNET_DONT:
    1304            0 :                 switch (Q_HIM(q)) {
    1305            0 :                 case Q_YES:
    1306            0 :                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO);
    1307            0 :                         _send_negotiate(telnet, TELNET_DONT, telopt);
    1308            0 :                         break;
    1309            0 :                 case Q_WANTYES:
    1310            0 :                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES_OP);
    1311            0 :                         break;
    1312            0 :                 case Q_WANTNO_OP:
    1313            0 :                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO);
    1314            0 :                         break;
    1315              :                 }
    1316            0 :                 break;
    1317              :         }
    1318              : }
    1319              : 
    1320              : /* send non-command data (escapes IAC bytes) */
    1321            0 : void telnet_send(telnet_t *telnet, const char *buffer,
    1322              :                 size_t size) {
    1323              :         size_t i, l;
    1324              : 
    1325            0 :         for (l = i = 0; i != size; ++i) {
    1326              :                 /* dump prior portion of text, send escaped bytes */
    1327            0 :                 if (buffer[i] == (char)TELNET_IAC) {
    1328              :                         /* dump prior text if any */
    1329            0 :                         if (i != l) {
    1330            0 :                                 _send(telnet, buffer + l, i - l);
    1331              :                         }
    1332            0 :                         l = i + 1;
    1333              : 
    1334              :                         /* send escape */
    1335            0 :                         telnet_iac(telnet, TELNET_IAC);
    1336              :                 }
    1337              :         }
    1338              : 
    1339              :         /* send whatever portion of buffer is left */
    1340            0 :         if (i != l) {
    1341            0 :                 _send(telnet, buffer + l, i - l);
    1342              :         }
    1343            0 : }
    1344              : 
    1345              : /* send non-command text (escapes IAC bytes and does NVT translation) */
    1346            0 : void telnet_send_text(telnet_t *telnet, const char *buffer,
    1347              :                 size_t size) {
    1348              :         size_t i, l;
    1349              : 
    1350            0 :         for (l = i = 0; i != size; ++i) {
    1351              :                 /* dump prior portion of text, send escaped bytes */
    1352            0 :                 if (buffer[i] == (char)TELNET_IAC) {
    1353              :                         /* dump prior text if any */
    1354            0 :                         if (i != l) {
    1355            0 :                                 _send(telnet, buffer + l, i - l);
    1356              :                         }
    1357            0 :                         l = i + 1;
    1358              : 
    1359              :                         /* send escape */
    1360            0 :                         telnet_iac(telnet, TELNET_IAC);
    1361              :                 }
    1362              :                 /* special characters if not in BINARY mode */
    1363            0 :                 else if (!(telnet->flags & TELNET_FLAG_TRANSMIT_BINARY) &&
    1364            0 :                                  (buffer[i] == '\r' || buffer[i] == '\n')) {
    1365              :                         /* dump prior portion of text */
    1366            0 :                         if (i != l) {
    1367            0 :                                 _send(telnet, buffer + l, i - l);
    1368              :                         }
    1369            0 :                         l = i + 1;
    1370              : 
    1371              :                         /* automatic translation of \r -> CRNUL */
    1372            0 :                         if (buffer[i] == '\r') {
    1373            0 :                                 _send(telnet, CRNUL, 2);
    1374              :                         }
    1375              :                         /* automatic translation of \n -> CRLF */
    1376              :                         else {
    1377            0 :                                 _send(telnet, CRLF, 2);
    1378              :                         }
    1379              :                 }
    1380              :         }
    1381              : 
    1382              :         /* send whatever portion of buffer is left */
    1383            0 :         if (i != l) {
    1384            0 :                 _send(telnet, buffer + l, i - l);
    1385              :         }
    1386            0 : }
    1387              : 
    1388              : /* send subnegotiation header */
    1389            0 : void telnet_begin_sb(telnet_t *telnet, unsigned char telopt) {
    1390              :         unsigned char sb[3];
    1391            0 :         sb[0] = TELNET_IAC;
    1392            0 :         sb[1] = TELNET_SB;
    1393            0 :         sb[2] = telopt;
    1394            0 :         _sendu(telnet, sb, 3);
    1395            0 : }
    1396              : 
    1397              : 
    1398              : /* send complete subnegotiation */
    1399            0 : void telnet_subnegotiation(telnet_t *telnet, unsigned char telopt,
    1400              :                 const char *buffer, size_t size) {
    1401              :         unsigned char bytes[5];
    1402            0 :         bytes[0] = TELNET_IAC;
    1403            0 :         bytes[1] = TELNET_SB;
    1404            0 :         bytes[2] = telopt;
    1405            0 :         bytes[3] = TELNET_IAC;
    1406            0 :         bytes[4] = TELNET_SE;
    1407              : 
    1408            0 :         _sendu(telnet, bytes, 3);
    1409            0 :         telnet_send(telnet, buffer, size);
    1410            0 :         _sendu(telnet, bytes + 3, 2);
    1411              : 
    1412              : #if defined(HAVE_ZLIB)
    1413              :         /* if we're a proxy and we just sent the COMPRESS2 marker, we must
    1414              :          * make sure all further data is compressed if not already.
    1415              :          */
    1416              :         if (telnet->flags & TELNET_FLAG_PROXY &&
    1417              :                         telopt == TELNET_TELOPT_COMPRESS2) {
    1418              :                 telnet_event_t ev;
    1419              : 
    1420              :                 if (_init_zlib(telnet, 1, 1) != TELNET_EOK)
    1421              :                         return;
    1422              : 
    1423              :                 /* notify app that compression was enabled */
    1424              :                 ev.type = TELNET_EV_COMPRESS;
    1425              :                 ev.compress.state = 1;
    1426              :                 telnet->eh(telnet, &ev, telnet->ud);
    1427              :         }
    1428              : #endif /* defined(HAVE_ZLIB) */
    1429            0 : }
    1430              : 
    1431            0 : void telnet_begin_compress2(telnet_t *telnet) {
    1432              : #if defined(HAVE_ZLIB)
    1433              :         static const unsigned char compress2[] = { TELNET_IAC, TELNET_SB,
    1434              :                         TELNET_TELOPT_COMPRESS2, TELNET_IAC, TELNET_SE };
    1435              : 
    1436              :         telnet_event_t ev;
    1437              : 
    1438              :         /* attempt to create output stream first, bail if we can't */
    1439              :         if (_init_zlib(telnet, 1, 0) != TELNET_EOK)
    1440              :                 return;
    1441              : 
    1442              :         /* send compression marker.  we send directly to the event handler
    1443              :          * instead of passing through _send because _send would result in
    1444              :          * the compress marker itself being compressed.
    1445              :          */
    1446              :         ev.type = TELNET_EV_SEND;
    1447              :         ev.data.buffer = (const char*)compress2;
    1448              :         ev.data.size = sizeof(compress2);
    1449              :         telnet->eh(telnet, &ev, telnet->ud);
    1450              : 
    1451              :         /* notify app that compression was successfully enabled */
    1452              :         ev.type = TELNET_EV_COMPRESS;
    1453              :         ev.compress.state = 1;
    1454              :         telnet->eh(telnet, &ev, telnet->ud);
    1455              : #endif /* defined(HAVE_ZLIB) */
    1456            0 : }
    1457              : 
    1458              : /* send formatted data with \r and \n translation in addition to IAC IAC */
    1459            0 : int telnet_vprintf(telnet_t *telnet, const char *fmt, va_list va) {
    1460              :         char buffer[1024];
    1461            0 :         char *output = buffer;
    1462              :         int rs, i, l;
    1463              : 
    1464              :         /* format */
    1465              :         va_list va2;
    1466            0 :         va_copy(va2, va);
    1467            0 :         rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
    1468            0 :         if (rs >= sizeof(buffer)) {
    1469            0 :                 output = (char*)malloc(rs + 1);
    1470            0 :                 if (output == 0) {
    1471            0 :                         _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
    1472            0 :                                         "malloc() failed: %s", strerror(errno));
    1473            0 :             va_end(va2);
    1474            0 :             va_end(va);
    1475            0 :                         return -1;
    1476              :                 }
    1477            0 :                 rs = vsnprintf(output, rs + 1, fmt, va2);
    1478              :         }
    1479            0 :         va_end(va2);
    1480            0 :         va_end(va);
    1481              : 
    1482              :         /* send */
    1483            0 :         for (l = i = 0; i != rs; ++i) {
    1484              :                 /* special characters */
    1485            0 :                 if (output[i] == (char)TELNET_IAC || output[i] == '\r' ||
    1486            0 :                                 output[i] == '\n') {
    1487              :                         /* dump prior portion of text */
    1488            0 :                         if (i != l)
    1489            0 :                                 _send(telnet, output + l, i - l);
    1490            0 :                         l = i + 1;
    1491              : 
    1492              :                         /* IAC -> IAC IAC */
    1493            0 :                         if (output[i] == (char)TELNET_IAC)
    1494            0 :                                 telnet_iac(telnet, TELNET_IAC);
    1495              :                         /* automatic translation of \r -> CRNUL */
    1496            0 :                         else if (output[i] == '\r')
    1497            0 :                                 _send(telnet, CRNUL, 2);
    1498              :                         /* automatic translation of \n -> CRLF */
    1499            0 :                         else if (output[i] == '\n')
    1500            0 :                                 _send(telnet, CRLF, 2);
    1501              :                 }
    1502              :         }
    1503              : 
    1504              :         /* send whatever portion of output is left */
    1505            0 :         if (i != l) {
    1506            0 :                 _send(telnet, output + l, i - l);
    1507              :         }
    1508              : 
    1509              :         /* free allocated memory, if any */
    1510            0 :         if (output != buffer) {
    1511            0 :                 free(output);
    1512              :         }
    1513              : 
    1514            0 :         return rs;
    1515              : }
    1516              : 
    1517              : /* see telnet_vprintf */
    1518            0 : int telnet_printf(telnet_t *telnet, const char *fmt, ...) {
    1519              :         va_list va;
    1520              :         int rs;
    1521              : 
    1522            0 :         va_start(va, fmt);
    1523            0 :         rs = telnet_vprintf(telnet, fmt, va);
    1524            0 :         va_end(va);
    1525              : 
    1526            0 :         return rs;
    1527              : }
    1528              : 
    1529              : /* send formatted data through telnet_send */
    1530            0 : int telnet_raw_vprintf(telnet_t *telnet, const char *fmt, va_list va) {
    1531              :         char buffer[1024];
    1532            0 :         char *output = buffer;
    1533              :         int rs;
    1534              : 
    1535              :         /* format; allocate more space if necessary */
    1536              :         va_list va2;
    1537            0 :         va_copy(va2, va);
    1538            0 :         rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
    1539            0 :         if (rs >= sizeof(buffer)) {
    1540            0 :                 output = (char*)malloc(rs + 1);
    1541            0 :                 if (output == 0) {
    1542            0 :                         _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
    1543            0 :                                         "malloc() failed: %s", strerror(errno));
    1544            0 :             va_end(va);
    1545            0 :             va_end(va2);
    1546            0 :                         return -1;
    1547              :                 }
    1548            0 :                 rs = vsnprintf(output, rs + 1, fmt, va2);
    1549              :         }
    1550            0 :         va_end(va2);
    1551            0 :         va_end(va);
    1552              : 
    1553              :         /* send out the formatted data */
    1554            0 :         telnet_send(telnet, output, rs);
    1555              : 
    1556              :         /* release allocated memory, if any */
    1557            0 :         if (output != buffer) {
    1558            0 :                 free(output);
    1559              :         }
    1560              : 
    1561            0 :         return rs;
    1562              : }
    1563              : 
    1564              : /* see telnet_raw_vprintf */
    1565            0 : int telnet_raw_printf(telnet_t *telnet, const char *fmt, ...) {
    1566              :         va_list va;
    1567              :         int rs;
    1568              : 
    1569            0 :         va_start(va, fmt);
    1570            0 :         rs = telnet_raw_vprintf(telnet, fmt, va);
    1571            0 :         va_end(va);
    1572              : 
    1573            0 :         return rs;
    1574              : }
    1575              : 
    1576              : /* begin NEW-ENVIRON subnegotation */
    1577            0 : void telnet_begin_newenviron(telnet_t *telnet, unsigned char cmd) {
    1578            0 :         telnet_begin_sb(telnet, TELNET_TELOPT_NEW_ENVIRON);
    1579            0 :         telnet_send(telnet, (const char *)&cmd, 1);
    1580            0 : }
    1581              : 
    1582              : /* send a NEW-ENVIRON value */
    1583            0 : void telnet_newenviron_value(telnet_t *telnet, unsigned char type,
    1584              :                 const char *string) {
    1585            0 :         telnet_send(telnet, (const char*)&type, 1);
    1586              : 
    1587            0 :         if (string != 0) {
    1588            0 :                 telnet_send(telnet, string, strlen(string));
    1589              :         }
    1590            0 : }
    1591              : 
    1592              : /* send TERMINAL-TYPE SEND command */
    1593            0 : void telnet_ttype_send(telnet_t *telnet) {
    1594              :     static const unsigned char SEND[] = { TELNET_IAC, TELNET_SB,
    1595              :                         TELNET_TELOPT_TTYPE, TELNET_TTYPE_SEND, TELNET_IAC, TELNET_SE };
    1596            0 :         _sendu(telnet, SEND, sizeof(SEND));
    1597            0 : }
    1598              : 
    1599              : /* send TERMINAL-TYPE IS command */
    1600            0 : void telnet_ttype_is(telnet_t *telnet, const char* ttype) {
    1601              :         static const unsigned char IS[] = { TELNET_IAC, TELNET_SB,
    1602              :                         TELNET_TELOPT_TTYPE, TELNET_TTYPE_IS };
    1603            0 :         _sendu(telnet, IS, sizeof(IS));
    1604            0 :         _send(telnet, ttype, strlen(ttype));
    1605            0 :         telnet_finish_sb(telnet);
    1606            0 : }
    1607              : 
    1608              : /* send ZMP data */
    1609            0 : void telnet_send_zmp(telnet_t *telnet, size_t argc, const char **argv) {
    1610              :         size_t i;
    1611              : 
    1612              :         /* ZMP header */
    1613            0 :         telnet_begin_zmp(telnet, argv[0]);
    1614              : 
    1615              :         /* send out each argument, including trailing NUL byte */
    1616            0 :         for (i = 1; i != argc; ++i)
    1617            0 :                 telnet_zmp_arg(telnet, argv[i]);
    1618              : 
    1619              :         /* ZMP footer */
    1620            0 :         telnet_finish_zmp(telnet);
    1621            0 : }
    1622              : 
    1623              : /* send ZMP data using varargs  */
    1624            0 : void telnet_send_vzmpv(telnet_t *telnet, va_list va) {
    1625              :         const char* arg;
    1626              : 
    1627              :         /* ZMP header */
    1628            0 :         telnet_begin_sb(telnet, TELNET_TELOPT_ZMP);
    1629              : 
    1630              :         /* send out each argument, including trailing NUL byte */
    1631            0 :         while ((arg = va_arg(va, const char *)) != 0)
    1632            0 :                 telnet_zmp_arg(telnet, arg);
    1633              : 
    1634              :         /* ZMP footer */
    1635            0 :         telnet_finish_zmp(telnet);
    1636            0 : }
    1637              : 
    1638              : /* see telnet_send_vzmpv */
    1639            0 : void telnet_send_zmpv(telnet_t *telnet, ...) {
    1640              :         va_list va;
    1641              : 
    1642            0 :         va_start(va, telnet);
    1643            0 :         telnet_send_vzmpv(telnet, va);
    1644            0 :         va_end(va);
    1645            0 : }
    1646              : 
    1647              : /* begin a ZMP command */
    1648            0 : void telnet_begin_zmp(telnet_t *telnet, const char *cmd) {
    1649            0 :         telnet_begin_sb(telnet, TELNET_TELOPT_ZMP);
    1650            0 :         telnet_zmp_arg(telnet, cmd);
    1651            0 : }
    1652              : 
    1653              : /* send a ZMP argument */
    1654            0 : void telnet_zmp_arg(telnet_t *telnet, const char* arg) {
    1655            0 :         telnet_send(telnet, arg, strlen(arg) + 1);
    1656            0 : }
        

Generated by: LCOV version 2.0-1