Annotation of embedaddon/curl/lib/telnet.c, revision 1.1.1.1

1.1       misho       1: /***************************************************************************
                      2:  *                                  _   _ ____  _
                      3:  *  Project                     ___| | | |  _ \| |
                      4:  *                             / __| | | | |_) | |
                      5:  *                            | (__| |_| |  _ <| |___
                      6:  *                             \___|\___/|_| \_\_____|
                      7:  *
                      8:  * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
                      9:  *
                     10:  * This software is licensed as described in the file COPYING, which
                     11:  * you should have received as part of this distribution. The terms
                     12:  * are also available at https://curl.haxx.se/docs/copyright.html.
                     13:  *
                     14:  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
                     15:  * copies of the Software, and permit persons to whom the Software is
                     16:  * furnished to do so, under the terms of the COPYING file.
                     17:  *
                     18:  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
                     19:  * KIND, either express or implied.
                     20:  *
                     21:  ***************************************************************************/
                     22: 
                     23: #include "curl_setup.h"
                     24: 
                     25: #ifndef CURL_DISABLE_TELNET
                     26: 
                     27: #ifdef HAVE_NETINET_IN_H
                     28: #include <netinet/in.h>
                     29: #endif
                     30: #ifdef HAVE_NETDB_H
                     31: #include <netdb.h>
                     32: #endif
                     33: #ifdef HAVE_ARPA_INET_H
                     34: #include <arpa/inet.h>
                     35: #endif
                     36: #ifdef HAVE_NET_IF_H
                     37: #include <net/if.h>
                     38: #endif
                     39: #ifdef HAVE_SYS_IOCTL_H
                     40: #include <sys/ioctl.h>
                     41: #endif
                     42: 
                     43: #ifdef HAVE_SYS_PARAM_H
                     44: #include <sys/param.h>
                     45: #endif
                     46: 
                     47: #include "urldata.h"
                     48: #include <curl/curl.h>
                     49: #include "transfer.h"
                     50: #include "sendf.h"
                     51: #include "telnet.h"
                     52: #include "connect.h"
                     53: #include "progress.h"
                     54: #include "system_win32.h"
                     55: #include "arpa_telnet.h"
                     56: #include "select.h"
                     57: #include "strcase.h"
                     58: #include "warnless.h"
                     59: 
                     60: /* The last 3 #include files should be in this order */
                     61: #include "curl_printf.h"
                     62: #include "curl_memory.h"
                     63: #include "memdebug.h"
                     64: 
                     65: #define SUBBUFSIZE 512
                     66: 
                     67: #define CURL_SB_CLEAR(x)  x->subpointer = x->subbuffer
                     68: #define CURL_SB_TERM(x)                                 \
                     69:   do {                                                  \
                     70:     x->subend = x->subpointer;                          \
                     71:     CURL_SB_CLEAR(x);                                   \
                     72:   } while(0)
                     73: #define CURL_SB_ACCUM(x,c)                                      \
                     74:   do {                                                          \
                     75:     if(x->subpointer < (x->subbuffer + sizeof(x->subbuffer)))   \
                     76:       *x->subpointer++ = (c);                                   \
                     77:   } while(0)
                     78: 
                     79: #define  CURL_SB_GET(x) ((*x->subpointer++)&0xff)
                     80: #define  CURL_SB_LEN(x) (x->subend - x->subpointer)
                     81: 
                     82: /* For posterity:
                     83: #define  CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
                     84: #define  CURL_SB_EOF(x) (x->subpointer >= x->subend) */
                     85: 
                     86: #ifdef CURL_DISABLE_VERBOSE_STRINGS
                     87: #define printoption(a,b,c,d)  Curl_nop_stmt
                     88: #endif
                     89: 
                     90: #ifdef USE_WINSOCK
                     91: typedef WSAEVENT (WINAPI *WSOCK2_EVENT)(void);
                     92: typedef FARPROC WSOCK2_FUNC;
                     93: static CURLcode check_wsock2(struct Curl_easy *data);
                     94: #endif
                     95: 
                     96: static
                     97: CURLcode telrcv(struct connectdata *,
                     98:                 const unsigned char *inbuf, /* Data received from socket */
                     99:                 ssize_t count);             /* Number of bytes received */
                    100: 
                    101: #ifndef CURL_DISABLE_VERBOSE_STRINGS
                    102: static void printoption(struct Curl_easy *data,
                    103:                         const char *direction,
                    104:                         int cmd, int option);
                    105: #endif
                    106: 
                    107: static void negotiate(struct connectdata *);
                    108: static void send_negotiation(struct connectdata *, int cmd, int option);
                    109: static void set_local_option(struct connectdata *conn,
                    110:                              int option, int newstate);
                    111: static void set_remote_option(struct connectdata *conn,
                    112:                               int option, int newstate);
                    113: 
                    114: static void printsub(struct Curl_easy *data,
                    115:                      int direction, unsigned char *pointer,
                    116:                      size_t length);
                    117: static void suboption(struct connectdata *);
                    118: static void sendsuboption(struct connectdata *conn, int option);
                    119: 
                    120: static CURLcode telnet_do(struct connectdata *conn, bool *done);
                    121: static CURLcode telnet_done(struct connectdata *conn,
                    122:                                  CURLcode, bool premature);
                    123: static CURLcode send_telnet_data(struct connectdata *conn,
                    124:                                  char *buffer, ssize_t nread);
                    125: 
                    126: /* For negotiation compliant to RFC 1143 */
                    127: #define CURL_NO          0
                    128: #define CURL_YES         1
                    129: #define CURL_WANTYES     2
                    130: #define CURL_WANTNO      3
                    131: 
                    132: #define CURL_EMPTY       0
                    133: #define CURL_OPPOSITE    1
                    134: 
                    135: /*
                    136:  * Telnet receiver states for fsm
                    137:  */
                    138: typedef enum
                    139: {
                    140:    CURL_TS_DATA = 0,
                    141:    CURL_TS_IAC,
                    142:    CURL_TS_WILL,
                    143:    CURL_TS_WONT,
                    144:    CURL_TS_DO,
                    145:    CURL_TS_DONT,
                    146:    CURL_TS_CR,
                    147:    CURL_TS_SB,   /* sub-option collection */
                    148:    CURL_TS_SE   /* looking for sub-option end */
                    149: } TelnetReceive;
                    150: 
                    151: struct TELNET {
                    152:   int please_negotiate;
                    153:   int already_negotiated;
                    154:   int us[256];
                    155:   int usq[256];
                    156:   int us_preferred[256];
                    157:   int him[256];
                    158:   int himq[256];
                    159:   int him_preferred[256];
                    160:   int subnegotiation[256];
                    161:   char subopt_ttype[32];             /* Set with suboption TTYPE */
                    162:   char subopt_xdisploc[128];         /* Set with suboption XDISPLOC */
                    163:   unsigned short subopt_wsx;         /* Set with suboption NAWS */
                    164:   unsigned short subopt_wsy;         /* Set with suboption NAWS */
                    165:   struct curl_slist *telnet_vars;    /* Environment variables */
                    166: 
                    167:   /* suboptions */
                    168:   unsigned char subbuffer[SUBBUFSIZE];
                    169:   unsigned char *subpointer, *subend;      /* buffer for sub-options */
                    170: 
                    171:   TelnetReceive telrcv_state;
                    172: };
                    173: 
                    174: 
                    175: /*
                    176:  * TELNET protocol handler.
                    177:  */
                    178: 
                    179: const struct Curl_handler Curl_handler_telnet = {
                    180:   "TELNET",                             /* scheme */
                    181:   ZERO_NULL,                            /* setup_connection */
                    182:   telnet_do,                            /* do_it */
                    183:   telnet_done,                          /* done */
                    184:   ZERO_NULL,                            /* do_more */
                    185:   ZERO_NULL,                            /* connect_it */
                    186:   ZERO_NULL,                            /* connecting */
                    187:   ZERO_NULL,                            /* doing */
                    188:   ZERO_NULL,                            /* proto_getsock */
                    189:   ZERO_NULL,                            /* doing_getsock */
                    190:   ZERO_NULL,                            /* domore_getsock */
                    191:   ZERO_NULL,                            /* perform_getsock */
                    192:   ZERO_NULL,                            /* disconnect */
                    193:   ZERO_NULL,                            /* readwrite */
                    194:   ZERO_NULL,                            /* connection_check */
                    195:   PORT_TELNET,                          /* defport */
                    196:   CURLPROTO_TELNET,                     /* protocol */
                    197:   PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
                    198: };
                    199: 
                    200: 
                    201: #ifdef USE_WINSOCK
                    202: static CURLcode
                    203: check_wsock2(struct Curl_easy *data)
                    204: {
                    205:   int err;
                    206:   WORD wVersionRequested;
                    207:   WSADATA wsaData;
                    208: 
                    209:   DEBUGASSERT(data);
                    210: 
                    211:   /* telnet requires at least WinSock 2.0 so ask for it. */
                    212:   wVersionRequested = MAKEWORD(2, 0);
                    213: 
                    214:   err = WSAStartup(wVersionRequested, &wsaData);
                    215: 
                    216:   /* We must've called this once already, so this call */
                    217:   /* should always succeed.  But, just in case... */
                    218:   if(err != 0) {
                    219:     failf(data,"WSAStartup failed (%d)",err);
                    220:     return CURLE_FAILED_INIT;
                    221:   }
                    222: 
                    223:   /* We have to have a WSACleanup call for every successful */
                    224:   /* WSAStartup call. */
                    225:   WSACleanup();
                    226: 
                    227:   /* Check that our version is supported */
                    228:   if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
                    229:       HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
                    230:       /* Our version isn't supported */
                    231:     failf(data, "insufficient winsock version to support "
                    232:           "telnet");
                    233:     return CURLE_FAILED_INIT;
                    234:   }
                    235: 
                    236:   /* Our version is supported */
                    237:   return CURLE_OK;
                    238: }
                    239: #endif
                    240: 
                    241: static
                    242: CURLcode init_telnet(struct connectdata *conn)
                    243: {
                    244:   struct TELNET *tn;
                    245: 
                    246:   tn = calloc(1, sizeof(struct TELNET));
                    247:   if(!tn)
                    248:     return CURLE_OUT_OF_MEMORY;
                    249: 
                    250:   conn->data->req.protop = tn; /* make us known */
                    251: 
                    252:   tn->telrcv_state = CURL_TS_DATA;
                    253: 
                    254:   /* Init suboptions */
                    255:   CURL_SB_CLEAR(tn);
                    256: 
                    257:   /* Set the options we want by default */
                    258:   tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
                    259:   tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
                    260: 
                    261:   /* To be compliant with previous releases of libcurl
                    262:      we enable this option by default. This behaviour
                    263:          can be changed thanks to the "BINARY" option in
                    264:          CURLOPT_TELNETOPTIONS
                    265:   */
                    266:   tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
                    267:   tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
                    268: 
                    269:   /* We must allow the server to echo what we sent
                    270:          but it is not necessary to request the server
                    271:          to do so (it might forces the server to close
                    272:          the connection). Hence, we ignore ECHO in the
                    273:          negotiate function
                    274:   */
                    275:   tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
                    276: 
                    277:   /* Set the subnegotiation fields to send information
                    278:     just after negotiation passed (do/will)
                    279: 
                    280:      Default values are (0,0) initialized by calloc.
                    281:      According to the RFC1013 it is valid:
                    282:      A value equal to zero is acceptable for the width (or height),
                    283:          and means that no character width (or height) is being sent.
                    284:          In this case, the width (or height) that will be assumed by the
                    285:          Telnet server is operating system specific (it will probably be
                    286:          based upon the terminal type information that may have been sent
                    287:          using the TERMINAL TYPE Telnet option). */
                    288:   tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES;
                    289:   return CURLE_OK;
                    290: }
                    291: 
                    292: static void negotiate(struct connectdata *conn)
                    293: {
                    294:   int i;
                    295:   struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
                    296: 
                    297:   for(i = 0; i < CURL_NTELOPTS; i++) {
                    298:     if(i == CURL_TELOPT_ECHO)
                    299:       continue;
                    300: 
                    301:     if(tn->us_preferred[i] == CURL_YES)
                    302:       set_local_option(conn, i, CURL_YES);
                    303: 
                    304:     if(tn->him_preferred[i] == CURL_YES)
                    305:       set_remote_option(conn, i, CURL_YES);
                    306:   }
                    307: }
                    308: 
                    309: #ifndef CURL_DISABLE_VERBOSE_STRINGS
                    310: static void printoption(struct Curl_easy *data,
                    311:                         const char *direction, int cmd, int option)
                    312: {
                    313:   if(data->set.verbose) {
                    314:     if(cmd == CURL_IAC) {
                    315:       if(CURL_TELCMD_OK(option))
                    316:         infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
                    317:       else
                    318:         infof(data, "%s IAC %d\n", direction, option);
                    319:     }
                    320:     else {
                    321:       const char *fmt = (cmd == CURL_WILL) ? "WILL" :
                    322:                         (cmd == CURL_WONT) ? "WONT" :
                    323:                         (cmd == CURL_DO) ? "DO" :
                    324:                         (cmd == CURL_DONT) ? "DONT" : 0;
                    325:       if(fmt) {
                    326:         const char *opt;
                    327:         if(CURL_TELOPT_OK(option))
                    328:           opt = CURL_TELOPT(option);
                    329:         else if(option == CURL_TELOPT_EXOPL)
                    330:           opt = "EXOPL";
                    331:         else
                    332:           opt = NULL;
                    333: 
                    334:         if(opt)
                    335:           infof(data, "%s %s %s\n", direction, fmt, opt);
                    336:         else
                    337:           infof(data, "%s %s %d\n", direction, fmt, option);
                    338:       }
                    339:       else
                    340:         infof(data, "%s %d %d\n", direction, cmd, option);
                    341:     }
                    342:   }
                    343: }
                    344: #endif
                    345: 
                    346: static void send_negotiation(struct connectdata *conn, int cmd, int option)
                    347: {
                    348:    unsigned char buf[3];
                    349:    ssize_t bytes_written;
                    350:    struct Curl_easy *data = conn->data;
                    351: 
                    352:    buf[0] = CURL_IAC;
                    353:    buf[1] = (unsigned char)cmd;
                    354:    buf[2] = (unsigned char)option;
                    355: 
                    356:    bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
                    357:    if(bytes_written < 0) {
                    358:      int err = SOCKERRNO;
                    359:      failf(data,"Sending data failed (%d)",err);
                    360:    }
                    361: 
                    362:    printoption(conn->data, "SENT", cmd, option);
                    363: }
                    364: 
                    365: static
                    366: void set_remote_option(struct connectdata *conn, int option, int newstate)
                    367: {
                    368:   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
                    369:   if(newstate == CURL_YES) {
                    370:     switch(tn->him[option]) {
                    371:     case CURL_NO:
                    372:       tn->him[option] = CURL_WANTYES;
                    373:       send_negotiation(conn, CURL_DO, option);
                    374:       break;
                    375: 
                    376:     case CURL_YES:
                    377:       /* Already enabled */
                    378:       break;
                    379: 
                    380:     case CURL_WANTNO:
                    381:       switch(tn->himq[option]) {
                    382:       case CURL_EMPTY:
                    383:         /* Already negotiating for CURL_YES, queue the request */
                    384:         tn->himq[option] = CURL_OPPOSITE;
                    385:         break;
                    386:       case CURL_OPPOSITE:
                    387:         /* Error: already queued an enable request */
                    388:         break;
                    389:       }
                    390:       break;
                    391: 
                    392:     case CURL_WANTYES:
                    393:       switch(tn->himq[option]) {
                    394:       case CURL_EMPTY:
                    395:         /* Error: already negotiating for enable */
                    396:         break;
                    397:       case CURL_OPPOSITE:
                    398:         tn->himq[option] = CURL_EMPTY;
                    399:         break;
                    400:       }
                    401:       break;
                    402:     }
                    403:   }
                    404:   else { /* NO */
                    405:     switch(tn->him[option]) {
                    406:     case CURL_NO:
                    407:       /* Already disabled */
                    408:       break;
                    409: 
                    410:     case CURL_YES:
                    411:       tn->him[option] = CURL_WANTNO;
                    412:       send_negotiation(conn, CURL_DONT, option);
                    413:       break;
                    414: 
                    415:     case CURL_WANTNO:
                    416:       switch(tn->himq[option]) {
                    417:       case CURL_EMPTY:
                    418:         /* Already negotiating for NO */
                    419:         break;
                    420:       case CURL_OPPOSITE:
                    421:         tn->himq[option] = CURL_EMPTY;
                    422:         break;
                    423:       }
                    424:       break;
                    425: 
                    426:     case CURL_WANTYES:
                    427:       switch(tn->himq[option]) {
                    428:       case CURL_EMPTY:
                    429:         tn->himq[option] = CURL_OPPOSITE;
                    430:         break;
                    431:       case CURL_OPPOSITE:
                    432:         break;
                    433:       }
                    434:       break;
                    435:     }
                    436:   }
                    437: }
                    438: 
                    439: static
                    440: void rec_will(struct connectdata *conn, int option)
                    441: {
                    442:   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
                    443:   switch(tn->him[option]) {
                    444:   case CURL_NO:
                    445:     if(tn->him_preferred[option] == CURL_YES) {
                    446:       tn->him[option] = CURL_YES;
                    447:       send_negotiation(conn, CURL_DO, option);
                    448:     }
                    449:     else
                    450:       send_negotiation(conn, CURL_DONT, option);
                    451: 
                    452:     break;
                    453: 
                    454:   case CURL_YES:
                    455:     /* Already enabled */
                    456:     break;
                    457: 
                    458:   case CURL_WANTNO:
                    459:     switch(tn->himq[option]) {
                    460:     case CURL_EMPTY:
                    461:       /* Error: DONT answered by WILL */
                    462:       tn->him[option] = CURL_NO;
                    463:       break;
                    464:     case CURL_OPPOSITE:
                    465:       /* Error: DONT answered by WILL */
                    466:       tn->him[option] = CURL_YES;
                    467:       tn->himq[option] = CURL_EMPTY;
                    468:       break;
                    469:     }
                    470:     break;
                    471: 
                    472:   case CURL_WANTYES:
                    473:     switch(tn->himq[option]) {
                    474:     case CURL_EMPTY:
                    475:       tn->him[option] = CURL_YES;
                    476:       break;
                    477:     case CURL_OPPOSITE:
                    478:       tn->him[option] = CURL_WANTNO;
                    479:       tn->himq[option] = CURL_EMPTY;
                    480:       send_negotiation(conn, CURL_DONT, option);
                    481:       break;
                    482:     }
                    483:     break;
                    484:   }
                    485: }
                    486: 
                    487: static
                    488: void rec_wont(struct connectdata *conn, int option)
                    489: {
                    490:   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
                    491:   switch(tn->him[option]) {
                    492:   case CURL_NO:
                    493:     /* Already disabled */
                    494:     break;
                    495: 
                    496:   case CURL_YES:
                    497:     tn->him[option] = CURL_NO;
                    498:     send_negotiation(conn, CURL_DONT, option);
                    499:     break;
                    500: 
                    501:   case CURL_WANTNO:
                    502:     switch(tn->himq[option]) {
                    503:     case CURL_EMPTY:
                    504:       tn->him[option] = CURL_NO;
                    505:       break;
                    506: 
                    507:     case CURL_OPPOSITE:
                    508:       tn->him[option] = CURL_WANTYES;
                    509:       tn->himq[option] = CURL_EMPTY;
                    510:       send_negotiation(conn, CURL_DO, option);
                    511:       break;
                    512:     }
                    513:     break;
                    514: 
                    515:   case CURL_WANTYES:
                    516:     switch(tn->himq[option]) {
                    517:     case CURL_EMPTY:
                    518:       tn->him[option] = CURL_NO;
                    519:       break;
                    520:     case CURL_OPPOSITE:
                    521:       tn->him[option] = CURL_NO;
                    522:       tn->himq[option] = CURL_EMPTY;
                    523:       break;
                    524:     }
                    525:     break;
                    526:   }
                    527: }
                    528: 
                    529: static void
                    530: set_local_option(struct connectdata *conn, int option, int newstate)
                    531: {
                    532:   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
                    533:   if(newstate == CURL_YES) {
                    534:     switch(tn->us[option]) {
                    535:     case CURL_NO:
                    536:       tn->us[option] = CURL_WANTYES;
                    537:       send_negotiation(conn, CURL_WILL, option);
                    538:       break;
                    539: 
                    540:     case CURL_YES:
                    541:       /* Already enabled */
                    542:       break;
                    543: 
                    544:     case CURL_WANTNO:
                    545:       switch(tn->usq[option]) {
                    546:       case CURL_EMPTY:
                    547:         /* Already negotiating for CURL_YES, queue the request */
                    548:         tn->usq[option] = CURL_OPPOSITE;
                    549:         break;
                    550:       case CURL_OPPOSITE:
                    551:         /* Error: already queued an enable request */
                    552:         break;
                    553:       }
                    554:       break;
                    555: 
                    556:     case CURL_WANTYES:
                    557:       switch(tn->usq[option]) {
                    558:       case CURL_EMPTY:
                    559:         /* Error: already negotiating for enable */
                    560:         break;
                    561:       case CURL_OPPOSITE:
                    562:         tn->usq[option] = CURL_EMPTY;
                    563:         break;
                    564:       }
                    565:       break;
                    566:     }
                    567:   }
                    568:   else { /* NO */
                    569:     switch(tn->us[option]) {
                    570:     case CURL_NO:
                    571:       /* Already disabled */
                    572:       break;
                    573: 
                    574:     case CURL_YES:
                    575:       tn->us[option] = CURL_WANTNO;
                    576:       send_negotiation(conn, CURL_WONT, option);
                    577:       break;
                    578: 
                    579:     case CURL_WANTNO:
                    580:       switch(tn->usq[option]) {
                    581:       case CURL_EMPTY:
                    582:         /* Already negotiating for NO */
                    583:         break;
                    584:       case CURL_OPPOSITE:
                    585:         tn->usq[option] = CURL_EMPTY;
                    586:         break;
                    587:       }
                    588:       break;
                    589: 
                    590:     case CURL_WANTYES:
                    591:       switch(tn->usq[option]) {
                    592:       case CURL_EMPTY:
                    593:         tn->usq[option] = CURL_OPPOSITE;
                    594:         break;
                    595:       case CURL_OPPOSITE:
                    596:         break;
                    597:       }
                    598:       break;
                    599:     }
                    600:   }
                    601: }
                    602: 
                    603: static
                    604: void rec_do(struct connectdata *conn, int option)
                    605: {
                    606:   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
                    607:   switch(tn->us[option]) {
                    608:   case CURL_NO:
                    609:     if(tn->us_preferred[option] == CURL_YES) {
                    610:       tn->us[option] = CURL_YES;
                    611:       send_negotiation(conn, CURL_WILL, option);
                    612:       if(tn->subnegotiation[option] == CURL_YES)
                    613:         /* transmission of data option */
                    614:         sendsuboption(conn, option);
                    615:     }
                    616:     else if(tn->subnegotiation[option] == CURL_YES) {
                    617:       /* send information to achieve this option*/
                    618:       tn->us[option] = CURL_YES;
                    619:       send_negotiation(conn, CURL_WILL, option);
                    620:       sendsuboption(conn, option);
                    621:     }
                    622:     else
                    623:       send_negotiation(conn, CURL_WONT, option);
                    624:     break;
                    625: 
                    626:   case CURL_YES:
                    627:     /* Already enabled */
                    628:     break;
                    629: 
                    630:   case CURL_WANTNO:
                    631:     switch(tn->usq[option]) {
                    632:     case CURL_EMPTY:
                    633:       /* Error: DONT answered by WILL */
                    634:       tn->us[option] = CURL_NO;
                    635:       break;
                    636:     case CURL_OPPOSITE:
                    637:       /* Error: DONT answered by WILL */
                    638:       tn->us[option] = CURL_YES;
                    639:       tn->usq[option] = CURL_EMPTY;
                    640:       break;
                    641:     }
                    642:     break;
                    643: 
                    644:   case CURL_WANTYES:
                    645:     switch(tn->usq[option]) {
                    646:     case CURL_EMPTY:
                    647:       tn->us[option] = CURL_YES;
                    648:       if(tn->subnegotiation[option] == CURL_YES) {
                    649:         /* transmission of data option */
                    650:         sendsuboption(conn, option);
                    651:       }
                    652:       break;
                    653:     case CURL_OPPOSITE:
                    654:       tn->us[option] = CURL_WANTNO;
                    655:       tn->himq[option] = CURL_EMPTY;
                    656:       send_negotiation(conn, CURL_WONT, option);
                    657:       break;
                    658:     }
                    659:     break;
                    660:   }
                    661: }
                    662: 
                    663: static
                    664: void rec_dont(struct connectdata *conn, int option)
                    665: {
                    666:   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
                    667:   switch(tn->us[option]) {
                    668:   case CURL_NO:
                    669:     /* Already disabled */
                    670:     break;
                    671: 
                    672:   case CURL_YES:
                    673:     tn->us[option] = CURL_NO;
                    674:     send_negotiation(conn, CURL_WONT, option);
                    675:     break;
                    676: 
                    677:   case CURL_WANTNO:
                    678:     switch(tn->usq[option]) {
                    679:     case CURL_EMPTY:
                    680:       tn->us[option] = CURL_NO;
                    681:       break;
                    682: 
                    683:     case CURL_OPPOSITE:
                    684:       tn->us[option] = CURL_WANTYES;
                    685:       tn->usq[option] = CURL_EMPTY;
                    686:       send_negotiation(conn, CURL_WILL, option);
                    687:       break;
                    688:     }
                    689:     break;
                    690: 
                    691:   case CURL_WANTYES:
                    692:     switch(tn->usq[option]) {
                    693:     case CURL_EMPTY:
                    694:       tn->us[option] = CURL_NO;
                    695:       break;
                    696:     case CURL_OPPOSITE:
                    697:       tn->us[option] = CURL_NO;
                    698:       tn->usq[option] = CURL_EMPTY;
                    699:       break;
                    700:     }
                    701:     break;
                    702:   }
                    703: }
                    704: 
                    705: 
                    706: static void printsub(struct Curl_easy *data,
                    707:                      int direction,             /* '<' or '>' */
                    708:                      unsigned char *pointer,    /* where suboption data is */
                    709:                      size_t length)             /* length of suboption data */
                    710: {
                    711:   if(data->set.verbose) {
                    712:     unsigned int i = 0;
                    713:     if(direction) {
                    714:       infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
                    715:       if(length >= 3) {
                    716:         int j;
                    717: 
                    718:         i = pointer[length-2];
                    719:         j = pointer[length-1];
                    720: 
                    721:         if(i != CURL_IAC || j != CURL_SE) {
                    722:           infof(data, "(terminated by ");
                    723:           if(CURL_TELOPT_OK(i))
                    724:             infof(data, "%s ", CURL_TELOPT(i));
                    725:           else if(CURL_TELCMD_OK(i))
                    726:             infof(data, "%s ", CURL_TELCMD(i));
                    727:           else
                    728:             infof(data, "%u ", i);
                    729:           if(CURL_TELOPT_OK(j))
                    730:             infof(data, "%s", CURL_TELOPT(j));
                    731:           else if(CURL_TELCMD_OK(j))
                    732:             infof(data, "%s", CURL_TELCMD(j));
                    733:           else
                    734:             infof(data, "%d", j);
                    735:           infof(data, ", not IAC SE!) ");
                    736:         }
                    737:       }
                    738:       length -= 2;
                    739:     }
                    740:     if(length < 1) {
                    741:       infof(data, "(Empty suboption?)");
                    742:       return;
                    743:     }
                    744: 
                    745:     if(CURL_TELOPT_OK(pointer[0])) {
                    746:       switch(pointer[0]) {
                    747:       case CURL_TELOPT_TTYPE:
                    748:       case CURL_TELOPT_XDISPLOC:
                    749:       case CURL_TELOPT_NEW_ENVIRON:
                    750:       case CURL_TELOPT_NAWS:
                    751:         infof(data, "%s", CURL_TELOPT(pointer[0]));
                    752:         break;
                    753:       default:
                    754:         infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
                    755:         break;
                    756:       }
                    757:     }
                    758:     else
                    759:       infof(data, "%d (unknown)", pointer[i]);
                    760: 
                    761:     switch(pointer[0]) {
                    762:     case CURL_TELOPT_NAWS:
                    763:       if(length > 4)
                    764:         infof(data, "Width: %d ; Height: %d", (pointer[1]<<8) | pointer[2],
                    765:               (pointer[3]<<8) | pointer[4]);
                    766:       break;
                    767:     default:
                    768:       switch(pointer[1]) {
                    769:       case CURL_TELQUAL_IS:
                    770:         infof(data, " IS");
                    771:         break;
                    772:       case CURL_TELQUAL_SEND:
                    773:         infof(data, " SEND");
                    774:         break;
                    775:       case CURL_TELQUAL_INFO:
                    776:         infof(data, " INFO/REPLY");
                    777:         break;
                    778:       case CURL_TELQUAL_NAME:
                    779:         infof(data, " NAME");
                    780:         break;
                    781:       }
                    782: 
                    783:       switch(pointer[0]) {
                    784:       case CURL_TELOPT_TTYPE:
                    785:       case CURL_TELOPT_XDISPLOC:
                    786:         pointer[length] = 0;
                    787:         infof(data, " \"%s\"", &pointer[2]);
                    788:         break;
                    789:       case CURL_TELOPT_NEW_ENVIRON:
                    790:         if(pointer[1] == CURL_TELQUAL_IS) {
                    791:           infof(data, " ");
                    792:           for(i = 3; i < length; i++) {
                    793:             switch(pointer[i]) {
                    794:             case CURL_NEW_ENV_VAR:
                    795:               infof(data, ", ");
                    796:               break;
                    797:             case CURL_NEW_ENV_VALUE:
                    798:               infof(data, " = ");
                    799:               break;
                    800:             default:
                    801:               infof(data, "%c", pointer[i]);
                    802:               break;
                    803:             }
                    804:           }
                    805:         }
                    806:         break;
                    807:       default:
                    808:         for(i = 2; i < length; i++)
                    809:           infof(data, " %.2x", pointer[i]);
                    810:         break;
                    811:       }
                    812:     }
                    813:     if(direction)
                    814:       infof(data, "\n");
                    815:   }
                    816: }
                    817: 
                    818: static CURLcode check_telnet_options(struct connectdata *conn)
                    819: {
                    820:   struct curl_slist *head;
                    821:   struct curl_slist *beg;
                    822:   char option_keyword[128] = "";
                    823:   char option_arg[256] = "";
                    824:   struct Curl_easy *data = conn->data;
                    825:   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
                    826:   CURLcode result = CURLE_OK;
                    827:   int binary_option;
                    828: 
                    829:   /* Add the user name as an environment variable if it
                    830:      was given on the command line */
                    831:   if(conn->bits.user_passwd) {
                    832:     msnprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
                    833:     beg = curl_slist_append(tn->telnet_vars, option_arg);
                    834:     if(!beg) {
                    835:       curl_slist_free_all(tn->telnet_vars);
                    836:       tn->telnet_vars = NULL;
                    837:       return CURLE_OUT_OF_MEMORY;
                    838:     }
                    839:     tn->telnet_vars = beg;
                    840:     tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
                    841:   }
                    842: 
                    843:   for(head = data->set.telnet_options; head; head = head->next) {
                    844:     if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
                    845:               option_keyword, option_arg) == 2) {
                    846: 
                    847:       /* Terminal type */
                    848:       if(strcasecompare(option_keyword, "TTYPE")) {
                    849:         strncpy(tn->subopt_ttype, option_arg, 31);
                    850:         tn->subopt_ttype[31] = 0; /* String termination */
                    851:         tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
                    852:         continue;
                    853:       }
                    854: 
                    855:       /* Display variable */
                    856:       if(strcasecompare(option_keyword, "XDISPLOC")) {
                    857:         strncpy(tn->subopt_xdisploc, option_arg, 127);
                    858:         tn->subopt_xdisploc[127] = 0; /* String termination */
                    859:         tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
                    860:         continue;
                    861:       }
                    862: 
                    863:       /* Environment variable */
                    864:       if(strcasecompare(option_keyword, "NEW_ENV")) {
                    865:         beg = curl_slist_append(tn->telnet_vars, option_arg);
                    866:         if(!beg) {
                    867:           result = CURLE_OUT_OF_MEMORY;
                    868:           break;
                    869:         }
                    870:         tn->telnet_vars = beg;
                    871:         tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
                    872:         continue;
                    873:       }
                    874: 
                    875:       /* Window Size */
                    876:       if(strcasecompare(option_keyword, "WS")) {
                    877:         if(sscanf(option_arg, "%hu%*[xX]%hu",
                    878:                   &tn->subopt_wsx, &tn->subopt_wsy) == 2)
                    879:           tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
                    880:         else {
                    881:           failf(data, "Syntax error in telnet option: %s", head->data);
                    882:           result = CURLE_TELNET_OPTION_SYNTAX;
                    883:           break;
                    884:         }
                    885:         continue;
                    886:       }
                    887: 
                    888:       /* To take care or not of the 8th bit in data exchange */
                    889:       if(strcasecompare(option_keyword, "BINARY")) {
                    890:         binary_option = atoi(option_arg);
                    891:         if(binary_option != 1) {
                    892:           tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
                    893:           tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
                    894:         }
                    895:         continue;
                    896:       }
                    897: 
                    898:       failf(data, "Unknown telnet option %s", head->data);
                    899:       result = CURLE_UNKNOWN_OPTION;
                    900:       break;
                    901:     }
                    902:     failf(data, "Syntax error in telnet option: %s", head->data);
                    903:     result = CURLE_TELNET_OPTION_SYNTAX;
                    904:     break;
                    905:   }
                    906: 
                    907:   if(result) {
                    908:     curl_slist_free_all(tn->telnet_vars);
                    909:     tn->telnet_vars = NULL;
                    910:   }
                    911: 
                    912:   return result;
                    913: }
                    914: 
                    915: /*
                    916:  * suboption()
                    917:  *
                    918:  * Look at the sub-option buffer, and try to be helpful to the other
                    919:  * side.
                    920:  */
                    921: 
                    922: static void suboption(struct connectdata *conn)
                    923: {
                    924:   struct curl_slist *v;
                    925:   unsigned char temp[2048];
                    926:   ssize_t bytes_written;
                    927:   size_t len;
                    928:   int err;
                    929:   char varname[128] = "";
                    930:   char varval[128] = "";
                    931:   struct Curl_easy *data = conn->data;
                    932:   struct TELNET *tn = (struct TELNET *)data->req.protop;
                    933: 
                    934:   printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2);
                    935:   switch(CURL_SB_GET(tn)) {
                    936:     case CURL_TELOPT_TTYPE:
                    937:       len = strlen(tn->subopt_ttype) + 4 + 2;
                    938:       msnprintf((char *)temp, sizeof(temp),
                    939:                 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
                    940:                 CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
                    941:       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
                    942:       if(bytes_written < 0) {
                    943:         err = SOCKERRNO;
                    944:         failf(data,"Sending data failed (%d)",err);
                    945:       }
                    946:       printsub(data, '>', &temp[2], len-2);
                    947:       break;
                    948:     case CURL_TELOPT_XDISPLOC:
                    949:       len = strlen(tn->subopt_xdisploc) + 4 + 2;
                    950:       msnprintf((char *)temp, sizeof(temp),
                    951:                 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
                    952:                 CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
                    953:       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
                    954:       if(bytes_written < 0) {
                    955:         err = SOCKERRNO;
                    956:         failf(data,"Sending data failed (%d)",err);
                    957:       }
                    958:       printsub(data, '>', &temp[2], len-2);
                    959:       break;
                    960:     case CURL_TELOPT_NEW_ENVIRON:
                    961:       msnprintf((char *)temp, sizeof(temp),
                    962:                 "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
                    963:                 CURL_TELQUAL_IS);
                    964:       len = 4;
                    965: 
                    966:       for(v = tn->telnet_vars; v; v = v->next) {
                    967:         size_t tmplen = (strlen(v->data) + 1);
                    968:         /* Add the variable only if it fits */
                    969:         if(len + tmplen < (int)sizeof(temp)-6) {
                    970:           if(sscanf(v->data, "%127[^,],%127s", varname, varval)) {
                    971:             msnprintf((char *)&temp[len], sizeof(temp) - len,
                    972:                       "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
                    973:                       CURL_NEW_ENV_VALUE, varval);
                    974:             len += tmplen;
                    975:           }
                    976:         }
                    977:       }
                    978:       msnprintf((char *)&temp[len], sizeof(temp) - len,
                    979:                 "%c%c", CURL_IAC, CURL_SE);
                    980:       len += 2;
                    981:       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
                    982:       if(bytes_written < 0) {
                    983:         err = SOCKERRNO;
                    984:         failf(data,"Sending data failed (%d)",err);
                    985:       }
                    986:       printsub(data, '>', &temp[2], len-2);
                    987:       break;
                    988:   }
                    989:   return;
                    990: }
                    991: 
                    992: 
                    993: /*
                    994:  * sendsuboption()
                    995:  *
                    996:  * Send suboption information to the server side.
                    997:  */
                    998: 
                    999: static void sendsuboption(struct connectdata *conn, int option)
                   1000: {
                   1001:   ssize_t bytes_written;
                   1002:   int err;
                   1003:   unsigned short x, y;
                   1004:   unsigned char *uc1, *uc2;
                   1005: 
                   1006:   struct Curl_easy *data = conn->data;
                   1007:   struct TELNET *tn = (struct TELNET *)data->req.protop;
                   1008: 
                   1009:   switch(option) {
                   1010:   case CURL_TELOPT_NAWS:
                   1011:     /* We prepare data to be sent */
                   1012:     CURL_SB_CLEAR(tn);
                   1013:     CURL_SB_ACCUM(tn, CURL_IAC);
                   1014:     CURL_SB_ACCUM(tn, CURL_SB);
                   1015:     CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
                   1016:     /* We must deal either with little or big endian processors */
                   1017:     /* Window size must be sent according to the 'network order' */
                   1018:     x = htons(tn->subopt_wsx);
                   1019:     y = htons(tn->subopt_wsy);
                   1020:     uc1 = (unsigned char *)&x;
                   1021:     uc2 = (unsigned char *)&y;
                   1022:     CURL_SB_ACCUM(tn, uc1[0]);
                   1023:     CURL_SB_ACCUM(tn, uc1[1]);
                   1024:     CURL_SB_ACCUM(tn, uc2[0]);
                   1025:     CURL_SB_ACCUM(tn, uc2[1]);
                   1026: 
                   1027:     CURL_SB_ACCUM(tn, CURL_IAC);
                   1028:     CURL_SB_ACCUM(tn, CURL_SE);
                   1029:     CURL_SB_TERM(tn);
                   1030:     /* data suboption is now ready */
                   1031: 
                   1032:     printsub(data, '>', (unsigned char *)tn->subbuffer + 2,
                   1033:              CURL_SB_LEN(tn)-2);
                   1034: 
                   1035:     /* we send the header of the suboption... */
                   1036:     bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
                   1037:     if(bytes_written < 0) {
                   1038:       err = SOCKERRNO;
                   1039:       failf(data, "Sending data failed (%d)", err);
                   1040:     }
                   1041:     /* ... then the window size with the send_telnet_data() function
                   1042:        to deal with 0xFF cases ... */
                   1043:     send_telnet_data(conn, (char *)tn->subbuffer + 3, 4);
                   1044:     /* ... and the footer */
                   1045:     bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer + 7, 2);
                   1046:     if(bytes_written < 0) {
                   1047:       err = SOCKERRNO;
                   1048:       failf(data, "Sending data failed (%d)", err);
                   1049:     }
                   1050:     break;
                   1051:   }
                   1052: }
                   1053: 
                   1054: 
                   1055: static
                   1056: CURLcode telrcv(struct connectdata *conn,
                   1057:                 const unsigned char *inbuf, /* Data received from socket */
                   1058:                 ssize_t count)              /* Number of bytes received */
                   1059: {
                   1060:   unsigned char c;
                   1061:   CURLcode result;
                   1062:   int in = 0;
                   1063:   int startwrite = -1;
                   1064:   struct Curl_easy *data = conn->data;
                   1065:   struct TELNET *tn = (struct TELNET *)data->req.protop;
                   1066: 
                   1067: #define startskipping()                                       \
                   1068:   if(startwrite >= 0) {                                       \
                   1069:     result = Curl_client_write(conn,                          \
                   1070:                                CLIENTWRITE_BODY,              \
                   1071:                                (char *)&inbuf[startwrite],    \
                   1072:                                in-startwrite);                \
                   1073:     if(result)                                                \
                   1074:       return result;                                          \
                   1075:   }                                                           \
                   1076:   startwrite = -1
                   1077: 
                   1078: #define writebyte() \
                   1079:     if(startwrite < 0) \
                   1080:       startwrite = in
                   1081: 
                   1082: #define bufferflush() startskipping()
                   1083: 
                   1084:   while(count--) {
                   1085:     c = inbuf[in];
                   1086: 
                   1087:     switch(tn->telrcv_state) {
                   1088:     case CURL_TS_CR:
                   1089:       tn->telrcv_state = CURL_TS_DATA;
                   1090:       if(c == '\0') {
                   1091:         startskipping();
                   1092:         break;   /* Ignore \0 after CR */
                   1093:       }
                   1094:       writebyte();
                   1095:       break;
                   1096: 
                   1097:     case CURL_TS_DATA:
                   1098:       if(c == CURL_IAC) {
                   1099:         tn->telrcv_state = CURL_TS_IAC;
                   1100:         startskipping();
                   1101:         break;
                   1102:       }
                   1103:       else if(c == '\r')
                   1104:         tn->telrcv_state = CURL_TS_CR;
                   1105:       writebyte();
                   1106:       break;
                   1107: 
                   1108:     case CURL_TS_IAC:
                   1109:     process_iac:
                   1110:       DEBUGASSERT(startwrite < 0);
                   1111:       switch(c) {
                   1112:       case CURL_WILL:
                   1113:         tn->telrcv_state = CURL_TS_WILL;
                   1114:         break;
                   1115:       case CURL_WONT:
                   1116:         tn->telrcv_state = CURL_TS_WONT;
                   1117:         break;
                   1118:       case CURL_DO:
                   1119:         tn->telrcv_state = CURL_TS_DO;
                   1120:         break;
                   1121:       case CURL_DONT:
                   1122:         tn->telrcv_state = CURL_TS_DONT;
                   1123:         break;
                   1124:       case CURL_SB:
                   1125:         CURL_SB_CLEAR(tn);
                   1126:         tn->telrcv_state = CURL_TS_SB;
                   1127:         break;
                   1128:       case CURL_IAC:
                   1129:         tn->telrcv_state = CURL_TS_DATA;
                   1130:         writebyte();
                   1131:         break;
                   1132:       case CURL_DM:
                   1133:       case CURL_NOP:
                   1134:       case CURL_GA:
                   1135:       default:
                   1136:         tn->telrcv_state = CURL_TS_DATA;
                   1137:         printoption(data, "RCVD", CURL_IAC, c);
                   1138:         break;
                   1139:       }
                   1140:       break;
                   1141: 
                   1142:       case CURL_TS_WILL:
                   1143:         printoption(data, "RCVD", CURL_WILL, c);
                   1144:         tn->please_negotiate = 1;
                   1145:         rec_will(conn, c);
                   1146:         tn->telrcv_state = CURL_TS_DATA;
                   1147:         break;
                   1148: 
                   1149:       case CURL_TS_WONT:
                   1150:         printoption(data, "RCVD", CURL_WONT, c);
                   1151:         tn->please_negotiate = 1;
                   1152:         rec_wont(conn, c);
                   1153:         tn->telrcv_state = CURL_TS_DATA;
                   1154:         break;
                   1155: 
                   1156:       case CURL_TS_DO:
                   1157:         printoption(data, "RCVD", CURL_DO, c);
                   1158:         tn->please_negotiate = 1;
                   1159:         rec_do(conn, c);
                   1160:         tn->telrcv_state = CURL_TS_DATA;
                   1161:         break;
                   1162: 
                   1163:       case CURL_TS_DONT:
                   1164:         printoption(data, "RCVD", CURL_DONT, c);
                   1165:         tn->please_negotiate = 1;
                   1166:         rec_dont(conn, c);
                   1167:         tn->telrcv_state = CURL_TS_DATA;
                   1168:         break;
                   1169: 
                   1170:       case CURL_TS_SB:
                   1171:         if(c == CURL_IAC)
                   1172:           tn->telrcv_state = CURL_TS_SE;
                   1173:         else
                   1174:           CURL_SB_ACCUM(tn, c);
                   1175:         break;
                   1176: 
                   1177:       case CURL_TS_SE:
                   1178:         if(c != CURL_SE) {
                   1179:           if(c != CURL_IAC) {
                   1180:             /*
                   1181:              * This is an error.  We only expect to get "IAC IAC" or "IAC SE".
                   1182:              * Several things may have happened.  An IAC was not doubled, the
                   1183:              * IAC SE was left off, or another option got inserted into the
                   1184:              * suboption are all possibilities.  If we assume that the IAC was
                   1185:              * not doubled, and really the IAC SE was left off, we could get
                   1186:              * into an infinite loop here.  So, instead, we terminate the
                   1187:              * suboption, and process the partial suboption if we can.
                   1188:              */
                   1189:             CURL_SB_ACCUM(tn, CURL_IAC);
                   1190:             CURL_SB_ACCUM(tn, c);
                   1191:             tn->subpointer -= 2;
                   1192:             CURL_SB_TERM(tn);
                   1193: 
                   1194:             printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
                   1195:             suboption(conn);   /* handle sub-option */
                   1196:             tn->telrcv_state = CURL_TS_IAC;
                   1197:             goto process_iac;
                   1198:           }
                   1199:           CURL_SB_ACCUM(tn, c);
                   1200:           tn->telrcv_state = CURL_TS_SB;
                   1201:         }
                   1202:         else {
                   1203:           CURL_SB_ACCUM(tn, CURL_IAC);
                   1204:           CURL_SB_ACCUM(tn, CURL_SE);
                   1205:           tn->subpointer -= 2;
                   1206:           CURL_SB_TERM(tn);
                   1207:           suboption(conn);   /* handle sub-option */
                   1208:           tn->telrcv_state = CURL_TS_DATA;
                   1209:         }
                   1210:         break;
                   1211:     }
                   1212:     ++in;
                   1213:   }
                   1214:   bufferflush();
                   1215:   return CURLE_OK;
                   1216: }
                   1217: 
                   1218: /* Escape and send a telnet data block */
                   1219: static CURLcode send_telnet_data(struct connectdata *conn,
                   1220:                                  char *buffer, ssize_t nread)
                   1221: {
                   1222:   ssize_t escapes, i, outlen;
                   1223:   unsigned char *outbuf = NULL;
                   1224:   CURLcode result = CURLE_OK;
                   1225:   ssize_t bytes_written, total_written;
                   1226: 
                   1227:   /* Determine size of new buffer after escaping */
                   1228:   escapes = 0;
                   1229:   for(i = 0; i < nread; i++)
                   1230:     if((unsigned char)buffer[i] == CURL_IAC)
                   1231:       escapes++;
                   1232:   outlen = nread + escapes;
                   1233: 
                   1234:   if(outlen == nread)
                   1235:     outbuf = (unsigned char *)buffer;
                   1236:   else {
                   1237:     ssize_t j;
                   1238:     outbuf = malloc(nread + escapes + 1);
                   1239:     if(!outbuf)
                   1240:       return CURLE_OUT_OF_MEMORY;
                   1241: 
                   1242:     j = 0;
                   1243:     for(i = 0; i < nread; i++) {
                   1244:       outbuf[j++] = buffer[i];
                   1245:       if((unsigned char)buffer[i] == CURL_IAC)
                   1246:         outbuf[j++] = CURL_IAC;
                   1247:     }
                   1248:     outbuf[j] = '\0';
                   1249:   }
                   1250: 
                   1251:   total_written = 0;
                   1252:   while(!result && total_written < outlen) {
                   1253:     /* Make sure socket is writable to avoid EWOULDBLOCK condition */
                   1254:     struct pollfd pfd[1];
                   1255:     pfd[0].fd = conn->sock[FIRSTSOCKET];
                   1256:     pfd[0].events = POLLOUT;
                   1257:     switch(Curl_poll(pfd, 1, -1)) {
                   1258:       case -1:                    /* error, abort writing */
                   1259:       case 0:                     /* timeout (will never happen) */
                   1260:         result = CURLE_SEND_ERROR;
                   1261:         break;
                   1262:       default:                    /* write! */
                   1263:         bytes_written = 0;
                   1264:         result = Curl_write(conn, conn->sock[FIRSTSOCKET],
                   1265:                             outbuf + total_written,
                   1266:                             outlen - total_written,
                   1267:                             &bytes_written);
                   1268:         total_written += bytes_written;
                   1269:         break;
                   1270:     }
                   1271:   }
                   1272: 
                   1273:   /* Free malloc copy if escaped */
                   1274:   if(outbuf != (unsigned char *)buffer)
                   1275:     free(outbuf);
                   1276: 
                   1277:   return result;
                   1278: }
                   1279: 
                   1280: static CURLcode telnet_done(struct connectdata *conn,
                   1281:                                  CURLcode status, bool premature)
                   1282: {
                   1283:   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
                   1284:   (void)status; /* unused */
                   1285:   (void)premature; /* not used */
                   1286: 
                   1287:   if(!tn)
                   1288:     return CURLE_OK;
                   1289: 
                   1290:   curl_slist_free_all(tn->telnet_vars);
                   1291:   tn->telnet_vars = NULL;
                   1292: 
                   1293:   Curl_safefree(conn->data->req.protop);
                   1294: 
                   1295:   return CURLE_OK;
                   1296: }
                   1297: 
                   1298: static CURLcode telnet_do(struct connectdata *conn, bool *done)
                   1299: {
                   1300:   CURLcode result;
                   1301:   struct Curl_easy *data = conn->data;
                   1302:   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
                   1303: #ifdef USE_WINSOCK
                   1304:   HMODULE wsock2;
                   1305:   WSOCK2_FUNC close_event_func;
                   1306:   WSOCK2_EVENT create_event_func;
                   1307:   WSOCK2_FUNC event_select_func;
                   1308:   WSOCK2_FUNC enum_netevents_func;
                   1309:   WSAEVENT event_handle;
                   1310:   WSANETWORKEVENTS events;
                   1311:   HANDLE stdin_handle;
                   1312:   HANDLE objs[2];
                   1313:   DWORD  obj_count;
                   1314:   DWORD  wait_timeout;
                   1315:   DWORD readfile_read;
                   1316:   int err;
                   1317: #else
                   1318:   int interval_ms;
                   1319:   struct pollfd pfd[2];
                   1320:   int poll_cnt;
                   1321:   curl_off_t total_dl = 0;
                   1322:   curl_off_t total_ul = 0;
                   1323: #endif
                   1324:   ssize_t nread;
                   1325:   struct curltime now;
                   1326:   bool keepon = TRUE;
                   1327:   char *buf = data->state.buffer;
                   1328:   struct TELNET *tn;
                   1329: 
                   1330:   *done = TRUE; /* unconditionally */
                   1331: 
                   1332:   result = init_telnet(conn);
                   1333:   if(result)
                   1334:     return result;
                   1335: 
                   1336:   tn = (struct TELNET *)data->req.protop;
                   1337: 
                   1338:   result = check_telnet_options(conn);
                   1339:   if(result)
                   1340:     return result;
                   1341: 
                   1342: #ifdef USE_WINSOCK
                   1343:   /*
                   1344:   ** This functionality only works with WinSock >= 2.0.  So,
                   1345:   ** make sure we have it.
                   1346:   */
                   1347:   result = check_wsock2(data);
                   1348:   if(result)
                   1349:     return result;
                   1350: 
                   1351:   /* OK, so we have WinSock 2.0.  We need to dynamically */
                   1352:   /* load ws2_32.dll and get the function pointers we need. */
                   1353:   wsock2 = Curl_load_library(TEXT("WS2_32.DLL"));
                   1354:   if(wsock2 == NULL) {
                   1355:     failf(data, "failed to load WS2_32.DLL (%u)", GetLastError());
                   1356:     return CURLE_FAILED_INIT;
                   1357:   }
                   1358: 
                   1359:   /* Grab a pointer to WSACreateEvent */
                   1360:   create_event_func =
                   1361:     CURLX_FUNCTION_CAST(WSOCK2_EVENT,
                   1362:                         (GetProcAddress(wsock2, "WSACreateEvent")));
                   1363:   if(create_event_func == NULL) {
                   1364:     failf(data, "failed to find WSACreateEvent function (%u)", GetLastError());
                   1365:     FreeLibrary(wsock2);
                   1366:     return CURLE_FAILED_INIT;
                   1367:   }
                   1368: 
                   1369:   /* And WSACloseEvent */
                   1370:   close_event_func = GetProcAddress(wsock2, "WSACloseEvent");
                   1371:   if(close_event_func == NULL) {
                   1372:     failf(data, "failed to find WSACloseEvent function (%u)", GetLastError());
                   1373:     FreeLibrary(wsock2);
                   1374:     return CURLE_FAILED_INIT;
                   1375:   }
                   1376: 
                   1377:   /* And WSAEventSelect */
                   1378:   event_select_func = GetProcAddress(wsock2, "WSAEventSelect");
                   1379:   if(event_select_func == NULL) {
                   1380:     failf(data, "failed to find WSAEventSelect function (%u)", GetLastError());
                   1381:     FreeLibrary(wsock2);
                   1382:     return CURLE_FAILED_INIT;
                   1383:   }
                   1384: 
                   1385:   /* And WSAEnumNetworkEvents */
                   1386:   enum_netevents_func = GetProcAddress(wsock2, "WSAEnumNetworkEvents");
                   1387:   if(enum_netevents_func == NULL) {
                   1388:     failf(data, "failed to find WSAEnumNetworkEvents function (%u)",
                   1389:           GetLastError());
                   1390:     FreeLibrary(wsock2);
                   1391:     return CURLE_FAILED_INIT;
                   1392:   }
                   1393: 
                   1394:   /* We want to wait for both stdin and the socket. Since
                   1395:   ** the select() function in winsock only works on sockets
                   1396:   ** we have to use the WaitForMultipleObjects() call.
                   1397:   */
                   1398: 
                   1399:   /* First, create a sockets event object */
                   1400:   event_handle = (WSAEVENT)create_event_func();
                   1401:   if(event_handle == WSA_INVALID_EVENT) {
                   1402:     failf(data, "WSACreateEvent failed (%d)", SOCKERRNO);
                   1403:     FreeLibrary(wsock2);
                   1404:     return CURLE_FAILED_INIT;
                   1405:   }
                   1406: 
                   1407:   /* Tell winsock what events we want to listen to */
                   1408:   if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
                   1409:      SOCKET_ERROR) {
                   1410:     close_event_func(event_handle);
                   1411:     FreeLibrary(wsock2);
                   1412:     return CURLE_OK;
                   1413:   }
                   1414: 
                   1415:   /* The get the Windows file handle for stdin */
                   1416:   stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
                   1417: 
                   1418:   /* Create the list of objects to wait for */
                   1419:   objs[0] = event_handle;
                   1420:   objs[1] = stdin_handle;
                   1421: 
                   1422:   /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
                   1423:      else use the old WaitForMultipleObjects() way */
                   1424:   if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
                   1425:      data->set.is_fread_set) {
                   1426:     /* Don't wait for stdin_handle, just wait for event_handle */
                   1427:     obj_count = 1;
                   1428:     /* Check stdin_handle per 100 milliseconds */
                   1429:     wait_timeout = 100;
                   1430:   }
                   1431:   else {
                   1432:     obj_count = 2;
                   1433:     wait_timeout = 1000;
                   1434:   }
                   1435: 
                   1436:   /* Keep on listening and act on events */
                   1437:   while(keepon) {
                   1438:     const DWORD buf_size = (DWORD)data->set.buffer_size;
                   1439:     DWORD waitret = WaitForMultipleObjects(obj_count, objs,
                   1440:                                            FALSE, wait_timeout);
                   1441:     switch(waitret) {
                   1442:     case WAIT_TIMEOUT:
                   1443:     {
                   1444:       for(;;) {
                   1445:         if(data->set.is_fread_set) {
                   1446:           size_t n;
                   1447:           /* read from user-supplied method */
                   1448:           n = data->state.fread_func(buf, 1, buf_size, data->state.in);
                   1449:           if(n == CURL_READFUNC_ABORT) {
                   1450:             keepon = FALSE;
                   1451:             result = CURLE_READ_ERROR;
                   1452:             break;
                   1453:           }
                   1454: 
                   1455:           if(n == CURL_READFUNC_PAUSE)
                   1456:             break;
                   1457: 
                   1458:           if(n == 0)                        /* no bytes */
                   1459:             break;
                   1460: 
                   1461:           /* fall through with number of bytes read */
                   1462:           readfile_read = (DWORD)n;
                   1463:         }
                   1464:         else {
                   1465:           /* read from stdin */
                   1466:           if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
                   1467:                             &readfile_read, NULL)) {
                   1468:             keepon = FALSE;
                   1469:             result = CURLE_READ_ERROR;
                   1470:             break;
                   1471:           }
                   1472: 
                   1473:           if(!readfile_read)
                   1474:             break;
                   1475: 
                   1476:           if(!ReadFile(stdin_handle, buf, buf_size,
                   1477:                        &readfile_read, NULL)) {
                   1478:             keepon = FALSE;
                   1479:             result = CURLE_READ_ERROR;
                   1480:             break;
                   1481:           }
                   1482:         }
                   1483: 
                   1484:         result = send_telnet_data(conn, buf, readfile_read);
                   1485:         if(result) {
                   1486:           keepon = FALSE;
                   1487:           break;
                   1488:         }
                   1489:       }
                   1490:     }
                   1491:     break;
                   1492: 
                   1493:     case WAIT_OBJECT_0 + 1:
                   1494:     {
                   1495:       if(!ReadFile(stdin_handle, buf, buf_size,
                   1496:                    &readfile_read, NULL)) {
                   1497:         keepon = FALSE;
                   1498:         result = CURLE_READ_ERROR;
                   1499:         break;
                   1500:       }
                   1501: 
                   1502:       result = send_telnet_data(conn, buf, readfile_read);
                   1503:       if(result) {
                   1504:         keepon = FALSE;
                   1505:         break;
                   1506:       }
                   1507:     }
                   1508:     break;
                   1509: 
                   1510:     case WAIT_OBJECT_0:
                   1511: 
                   1512:       events.lNetworkEvents = 0;
                   1513:       if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
                   1514:         err = SOCKERRNO;
                   1515:         if(err != EINPROGRESS) {
                   1516:           infof(data, "WSAEnumNetworkEvents failed (%d)", err);
                   1517:           keepon = FALSE;
                   1518:           result = CURLE_READ_ERROR;
                   1519:         }
                   1520:         break;
                   1521:       }
                   1522:       if(events.lNetworkEvents & FD_READ) {
                   1523:         /* read data from network */
                   1524:         result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread);
                   1525:         /* read would've blocked. Loop again */
                   1526:         if(result == CURLE_AGAIN)
                   1527:           break;
                   1528:         /* returned not-zero, this an error */
                   1529:         else if(result) {
                   1530:           keepon = FALSE;
                   1531:           break;
                   1532:         }
                   1533:         /* returned zero but actually received 0 or less here,
                   1534:            the server closed the connection and we bail out */
                   1535:         else if(nread <= 0) {
                   1536:           keepon = FALSE;
                   1537:           break;
                   1538:         }
                   1539: 
                   1540:         result = telrcv(conn, (unsigned char *) buf, nread);
                   1541:         if(result) {
                   1542:           keepon = FALSE;
                   1543:           break;
                   1544:         }
                   1545: 
                   1546:         /* Negotiate if the peer has started negotiating,
                   1547:            otherwise don't. We don't want to speak telnet with
                   1548:            non-telnet servers, like POP or SMTP. */
                   1549:         if(tn->please_negotiate && !tn->already_negotiated) {
                   1550:           negotiate(conn);
                   1551:           tn->already_negotiated = 1;
                   1552:         }
                   1553:       }
                   1554:       if(events.lNetworkEvents & FD_CLOSE) {
                   1555:         keepon = FALSE;
                   1556:       }
                   1557:       break;
                   1558: 
                   1559:     }
                   1560: 
                   1561:     if(data->set.timeout) {
                   1562:       now = Curl_now();
                   1563:       if(Curl_timediff(now, conn->created) >= data->set.timeout) {
                   1564:         failf(data, "Time-out");
                   1565:         result = CURLE_OPERATION_TIMEDOUT;
                   1566:         keepon = FALSE;
                   1567:       }
                   1568:     }
                   1569:   }
                   1570: 
                   1571:   /* We called WSACreateEvent, so call WSACloseEvent */
                   1572:   if(!close_event_func(event_handle)) {
                   1573:     infof(data, "WSACloseEvent failed (%d)", SOCKERRNO);
                   1574:   }
                   1575: 
                   1576:   /* "Forget" pointers into the library we're about to free */
                   1577:   create_event_func = NULL;
                   1578:   close_event_func = NULL;
                   1579:   event_select_func = NULL;
                   1580:   enum_netevents_func = NULL;
                   1581: 
                   1582:   /* We called LoadLibrary, so call FreeLibrary */
                   1583:   if(!FreeLibrary(wsock2))
                   1584:     infof(data, "FreeLibrary(wsock2) failed (%u)", GetLastError());
                   1585: #else
                   1586:   pfd[0].fd = sockfd;
                   1587:   pfd[0].events = POLLIN;
                   1588: 
                   1589:   if(data->set.is_fread_set) {
                   1590:     poll_cnt = 1;
                   1591:     interval_ms = 100; /* poll user-supplied read function */
                   1592:   }
                   1593:   else {
                   1594:     /* really using fread, so infile is a FILE* */
                   1595:     pfd[1].fd = fileno((FILE *)data->state.in);
                   1596:     pfd[1].events = POLLIN;
                   1597:     poll_cnt = 2;
                   1598:     interval_ms = 1 * 1000;
                   1599:   }
                   1600: 
                   1601:   while(keepon) {
                   1602:     switch(Curl_poll(pfd, poll_cnt, interval_ms)) {
                   1603:     case -1:                    /* error, stop reading */
                   1604:       keepon = FALSE;
                   1605:       continue;
                   1606:     case 0:                     /* timeout */
                   1607:       pfd[0].revents = 0;
                   1608:       pfd[1].revents = 0;
                   1609:       /* FALLTHROUGH */
                   1610:     default:                    /* read! */
                   1611:       if(pfd[0].revents & POLLIN) {
                   1612:         /* read data from network */
                   1613:         result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread);
                   1614:         /* read would've blocked. Loop again */
                   1615:         if(result == CURLE_AGAIN)
                   1616:           break;
                   1617:         /* returned not-zero, this an error */
                   1618:         if(result) {
                   1619:           keepon = FALSE;
                   1620:           break;
                   1621:         }
                   1622:         /* returned zero but actually received 0 or less here,
                   1623:            the server closed the connection and we bail out */
                   1624:         else if(nread <= 0) {
                   1625:           keepon = FALSE;
                   1626:           break;
                   1627:         }
                   1628: 
                   1629:         total_dl += nread;
                   1630:         Curl_pgrsSetDownloadCounter(data, total_dl);
                   1631:         result = telrcv(conn, (unsigned char *)buf, nread);
                   1632:         if(result) {
                   1633:           keepon = FALSE;
                   1634:           break;
                   1635:         }
                   1636: 
                   1637:         /* Negotiate if the peer has started negotiating,
                   1638:            otherwise don't. We don't want to speak telnet with
                   1639:            non-telnet servers, like POP or SMTP. */
                   1640:         if(tn->please_negotiate && !tn->already_negotiated) {
                   1641:           negotiate(conn);
                   1642:           tn->already_negotiated = 1;
                   1643:         }
                   1644:       }
                   1645: 
                   1646:       nread = 0;
                   1647:       if(poll_cnt == 2) {
                   1648:         if(pfd[1].revents & POLLIN) { /* read from in file */
                   1649:           nread = read(pfd[1].fd, buf, data->set.buffer_size);
                   1650:         }
                   1651:       }
                   1652:       else {
                   1653:         /* read from user-supplied method */
                   1654:         nread = (int)data->state.fread_func(buf, 1, data->set.buffer_size,
                   1655:                                             data->state.in);
                   1656:         if(nread == CURL_READFUNC_ABORT) {
                   1657:           keepon = FALSE;
                   1658:           break;
                   1659:         }
                   1660:         if(nread == CURL_READFUNC_PAUSE)
                   1661:           break;
                   1662:       }
                   1663: 
                   1664:       if(nread > 0) {
                   1665:         result = send_telnet_data(conn, buf, nread);
                   1666:         if(result) {
                   1667:           keepon = FALSE;
                   1668:           break;
                   1669:         }
                   1670:         total_ul += nread;
                   1671:         Curl_pgrsSetUploadCounter(data, total_ul);
                   1672:       }
                   1673:       else if(nread < 0)
                   1674:         keepon = FALSE;
                   1675: 
                   1676:       break;
                   1677:     } /* poll switch statement */
                   1678: 
                   1679:     if(data->set.timeout) {
                   1680:       now = Curl_now();
                   1681:       if(Curl_timediff(now, conn->created) >= data->set.timeout) {
                   1682:         failf(data, "Time-out");
                   1683:         result = CURLE_OPERATION_TIMEDOUT;
                   1684:         keepon = FALSE;
                   1685:       }
                   1686:     }
                   1687: 
                   1688:     if(Curl_pgrsUpdate(conn)) {
                   1689:       result = CURLE_ABORTED_BY_CALLBACK;
                   1690:       break;
                   1691:     }
                   1692:   }
                   1693: #endif
                   1694:   /* mark this as "no further transfer wanted" */
                   1695:   Curl_setup_transfer(data, -1, -1, FALSE, -1);
                   1696: 
                   1697:   return result;
                   1698: }
                   1699: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>