File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / telnet.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>