• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_FALSE
73 #define CURL_SB_ACCUM(x,c)                                      \
74   do {                                                          \
75     if(x->subpointer < (x->subbuffer + sizeof(x->subbuffer)))   \
76       *x->subpointer++ = (c);                                   \
77   } WHILE_FALSE
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
check_wsock2(struct Curl_easy * data)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
init_telnet(struct connectdata * conn)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 
negotiate(struct connectdata * conn)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
printoption(struct Curl_easy * data,const char * direction,int cmd,int option)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 
send_negotiation(struct connectdata * conn,int cmd,int option)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
set_remote_option(struct connectdata * conn,int option,int newstate)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
rec_will(struct connectdata * conn,int option)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
rec_wont(struct connectdata * conn,int option)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
set_local_option(struct connectdata * conn,int option,int newstate)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
rec_do(struct connectdata * conn,int option)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
rec_dont(struct connectdata * conn,int option)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 
printsub(struct Curl_easy * data,int direction,unsigned char * pointer,size_t length)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 
check_telnet_options(struct connectdata * conn)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 
suboption(struct connectdata * conn)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 
sendsuboption(struct connectdata * conn,int option)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
telrcv(struct connectdata * conn,const unsigned char * inbuf,ssize_t count)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 */
send_telnet_data(struct connectdata * conn,char * buffer,ssize_t nread)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 
telnet_done(struct connectdata * conn,CURLcode status,bool premature)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 
telnet_do(struct connectdata * conn,bool * done)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
1700