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