1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2008, 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 http://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  * $Id: telnet.c,v 1.109 2009-02-27 08:53:10 bagder Exp $
22  ***************************************************************************/
23 
24 #include "setup.h"
25 
26 #ifndef CURL_DISABLE_TELNET
27 /* -- WIN32 approved -- */
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33 
34 #if defined(WIN32)
35 #include <time.h>
36 #include <io.h>
37 #else
38 #ifdef HAVE_SYS_SOCKET_H
39 #include <sys/socket.h>
40 #endif
41 #include <netinet/in.h>
42 #ifdef HAVE_SYS_TIME_H
43 #include <sys/time.h>
44 #endif
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 #include <netdb.h>
49 #ifdef HAVE_ARPA_INET_H
50 #include <arpa/inet.h>
51 #endif
52 #ifdef HAVE_NET_IF_H
53 #include <net/if.h>
54 #endif
55 #ifdef HAVE_SYS_IOCTL_H
56 #include <sys/ioctl.h>
57 #endif
58 
59 #ifdef HAVE_SYS_PARAM_H
60 #include <sys/param.h>
61 #endif
62 
63 #endif  /* WIN32 */
64 
65 #include "urldata.h"
66 #include <curl/curl.h>
67 #include "transfer.h"
68 #include "sendf.h"
69 #include "telnet.h"
70 #include "connect.h"
71 
72 #define _MPRINTF_REPLACE /* use our functions only */
73 #include <curl/mprintf.h>
74 
75 #define  TELOPTS
76 #define  TELCMDS
77 
78 #include "arpa_telnet.h"
79 #include "memory.h"
80 #include "select.h"
81 #include "strequal.h"
82 #include "rawstr.h"
83 
84 /* The last #include file should be: */
85 #include "memdebug.h"
86 
87 #define SUBBUFSIZE 512
88 
89 #define CURL_SB_CLEAR(x)  x->subpointer = x->subbuffer;
90 #define CURL_SB_TERM(x)   { x->subend = x->subpointer; CURL_SB_CLEAR(x); }
91 #define CURL_SB_ACCUM(x,c) \
92   if(x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \
93     *x->subpointer++ = (c); \
94   }
95 
96 #define  CURL_SB_GET(x) ((*x->subpointer++)&0xff)
97 #define  CURL_SB_PEEK(x)   ((*x->subpointer)&0xff)
98 #define  CURL_SB_EOF(x) (x->subpointer >= x->subend)
99 #define  CURL_SB_LEN(x) (x->subend - x->subpointer)
100 
101 #ifdef CURL_DISABLE_VERBOSE_STRINGS
102 #define printoption(a,b,c,d)  do { } while(0)
103 #endif
104 
105 #ifdef USE_WINSOCK
106 typedef FARPROC WSOCK2_FUNC;
107 static CURLcode check_wsock2 ( struct SessionHandle *data );
108 #endif
109 
110 static
111 void telrcv(struct connectdata *,
112             const unsigned char *inbuf, /* Data received from socket */
113             ssize_t count);             /* Number of bytes received */
114 
115 #ifndef CURL_DISABLE_VERBOSE_STRINGS
116 static void printoption(struct SessionHandle *data,
117                         const char *direction,
118                         int cmd, int option);
119 #endif
120 
121 static void negotiate(struct connectdata *);
122 static void send_negotiation(struct connectdata *, int cmd, int option);
123 static void set_local_option(struct connectdata *, int cmd, int option);
124 static void set_remote_option(struct connectdata *, int cmd, int option);
125 
126 static void printsub(struct SessionHandle *data,
127                      int direction, unsigned char *pointer,
128                      size_t length);
129 static void suboption(struct connectdata *);
130 
131 static CURLcode telnet_do(struct connectdata *conn, bool *done);
132 static CURLcode telnet_done(struct connectdata *conn,
133                                  CURLcode, bool premature);
134 
135 /* For negotiation compliant to RFC 1143 */
136 #define CURL_NO          0
137 #define CURL_YES         1
138 #define CURL_WANTYES     2
139 #define CURL_WANTNO      3
140 
141 #define CURL_EMPTY       0
142 #define CURL_OPPOSITE    1
143 
144 /*
145  * Telnet receiver states for fsm
146  */
147 typedef enum
148 {
149    CURL_TS_DATA = 0,
150    CURL_TS_IAC,
151    CURL_TS_WILL,
152    CURL_TS_WONT,
153    CURL_TS_DO,
154    CURL_TS_DONT,
155    CURL_TS_CR,
156    CURL_TS_SB,   /* sub-option collection */
157    CURL_TS_SE   /* looking for sub-option end */
158 } TelnetReceive;
159 
160 struct TELNET {
161   int please_negotiate;
162   int already_negotiated;
163   int us[256];
164   int usq[256];
165   int us_preferred[256];
166   int him[256];
167   int himq[256];
168   int him_preferred[256];
169   char subopt_ttype[32];             /* Set with suboption TTYPE */
170   char subopt_xdisploc[128];          /* Set with suboption XDISPLOC */
171   struct curl_slist *telnet_vars; /* Environment variables */
172 
173   /* suboptions */
174   unsigned char subbuffer[SUBBUFSIZE];
175   unsigned char *subpointer, *subend;      /* buffer for sub-options */
176 
177   TelnetReceive telrcv_state;
178 };
179 
180 
181 /*
182  * TELNET protocol handler.
183  */
184 
185 const struct Curl_handler Curl_handler_telnet = {
186   "TELNET",                             /* scheme */
187   ZERO_NULL,                            /* setup_connection */
188   telnet_do,                            /* do_it */
189   telnet_done,                          /* done */
190   ZERO_NULL,                            /* do_more */
191   ZERO_NULL,                            /* connect_it */
192   ZERO_NULL,                            /* connecting */
193   ZERO_NULL,                            /* doing */
194   ZERO_NULL,                            /* proto_getsock */
195   ZERO_NULL,                            /* doing_getsock */
196   ZERO_NULL,                            /* perform_getsock */
197   ZERO_NULL,                            /* disconnect */
198   PORT_TELNET,                          /* defport */
199   PROT_TELNET                           /* protocol */
200 };
201 
202 
203 #ifdef USE_WINSOCK
204 static CURLcode
check_wsock2(struct SessionHandle * data)205 check_wsock2 ( struct SessionHandle *data )
206 {
207   int err;
208   WORD wVersionRequested;
209   WSADATA wsaData;
210 
211   DEBUGASSERT(data);
212 
213   /* telnet requires at least WinSock 2.0 so ask for it. */
214   wVersionRequested = MAKEWORD(2, 0);
215 
216   err = WSAStartup(wVersionRequested, &wsaData);
217 
218   /* We must've called this once already, so this call */
219   /* should always succeed.  But, just in case... */
220   if(err != 0) {
221     failf(data,"WSAStartup failed (%d)",err);
222     return CURLE_FAILED_INIT;
223   }
224 
225   /* We have to have a WSACleanup call for every successful */
226   /* WSAStartup call. */
227   WSACleanup();
228 
229   /* Check that our version is supported */
230   if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
231       HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
232       /* Our version isn't supported */
233       failf(data,"insufficient winsock version to support "
234             "telnet");
235       return CURLE_FAILED_INIT;
236   }
237 
238   /* Our version is supported */
239   return CURLE_OK;
240 }
241 #endif
242 
243 static
init_telnet(struct connectdata * conn)244 CURLcode init_telnet(struct connectdata *conn)
245 {
246   struct TELNET *tn;
247 
248   tn = calloc(1, sizeof(struct TELNET));
249   if(!tn)
250     return CURLE_OUT_OF_MEMORY;
251 
252   conn->data->state.proto.telnet = (void *)tn; /* make us known */
253 
254   tn->telrcv_state = CURL_TS_DATA;
255 
256   /* Init suboptions */
257   CURL_SB_CLEAR(tn);
258 
259   /* Set the options we want by default */
260   tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
261   tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
262   tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
263   tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
264 
265   return CURLE_OK;
266 }
267 
negotiate(struct connectdata * conn)268 static void negotiate(struct connectdata *conn)
269 {
270   int i;
271   struct TELNET *tn = (struct TELNET *) conn->data->state.proto.telnet;
272 
273   for(i = 0;i < CURL_NTELOPTS;i++)
274   {
275     if(tn->us_preferred[i] == CURL_YES)
276       set_local_option(conn, i, CURL_YES);
277 
278     if(tn->him_preferred[i] == CURL_YES)
279       set_remote_option(conn, i, CURL_YES);
280   }
281 }
282 
283 #ifndef CURL_DISABLE_VERBOSE_STRINGS
printoption(struct SessionHandle * data,const char * direction,int cmd,int option)284 static void printoption(struct SessionHandle *data,
285                         const char *direction, int cmd, int option)
286 {
287   const char *fmt;
288   const char *opt;
289 
290   if(data->set.verbose)
291   {
292     if(cmd == CURL_IAC)
293     {
294       if(CURL_TELCMD_OK(option))
295         infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
296       else
297         infof(data, "%s IAC %d\n", direction, option);
298     }
299     else
300     {
301       fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
302         (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
303       if(fmt)
304       {
305         if(CURL_TELOPT_OK(option))
306           opt = CURL_TELOPT(option);
307         else if(option == CURL_TELOPT_EXOPL)
308           opt = "EXOPL";
309         else
310           opt = NULL;
311 
312         if(opt)
313           infof(data, "%s %s %s\n", direction, fmt, opt);
314         else
315           infof(data, "%s %s %d\n", direction, fmt, option);
316       }
317       else
318         infof(data, "%s %d %d\n", direction, cmd, option);
319     }
320   }
321 }
322 #endif
323 
send_negotiation(struct connectdata * conn,int cmd,int option)324 static void send_negotiation(struct connectdata *conn, int cmd, int option)
325 {
326    unsigned char buf[3];
327    ssize_t bytes_written;
328    int err;
329    struct SessionHandle *data = conn->data;
330 
331    buf[0] = CURL_IAC;
332    buf[1] = (unsigned char)cmd;
333    buf[2] = (unsigned char)option;
334 
335    bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
336    if(bytes_written < 0) {
337      err = SOCKERRNO;
338      failf(data,"Sending data failed (%d)",err);
339    }
340 
341    printoption(conn->data, "SENT", cmd, option);
342 }
343 
344 static
set_remote_option(struct connectdata * conn,int option,int newstate)345 void set_remote_option(struct connectdata *conn, int option, int newstate)
346 {
347   struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
348   if(newstate == CURL_YES)
349   {
350     switch(tn->him[option])
351     {
352       case CURL_NO:
353         tn->him[option] = CURL_WANTYES;
354         send_negotiation(conn, CURL_DO, option);
355         break;
356 
357       case CURL_YES:
358         /* Already enabled */
359         break;
360 
361       case CURL_WANTNO:
362         switch(tn->himq[option])
363         {
364           case CURL_EMPTY:
365             /* Already negotiating for CURL_YES, queue the request */
366             tn->himq[option] = CURL_OPPOSITE;
367             break;
368           case CURL_OPPOSITE:
369             /* Error: already queued an enable request */
370             break;
371         }
372         break;
373 
374       case CURL_WANTYES:
375         switch(tn->himq[option])
376         {
377           case CURL_EMPTY:
378             /* Error: already negotiating for enable */
379             break;
380           case CURL_OPPOSITE:
381             tn->himq[option] = CURL_EMPTY;
382             break;
383         }
384         break;
385     }
386   }
387   else /* NO */
388   {
389     switch(tn->him[option])
390     {
391       case CURL_NO:
392         /* Already disabled */
393         break;
394 
395       case CURL_YES:
396         tn->him[option] = CURL_WANTNO;
397         send_negotiation(conn, CURL_DONT, option);
398         break;
399 
400       case CURL_WANTNO:
401         switch(tn->himq[option])
402         {
403           case CURL_EMPTY:
404             /* Already negotiating for NO */
405             break;
406           case CURL_OPPOSITE:
407             tn->himq[option] = CURL_EMPTY;
408             break;
409         }
410         break;
411 
412       case CURL_WANTYES:
413         switch(tn->himq[option])
414         {
415           case CURL_EMPTY:
416             tn->himq[option] = CURL_OPPOSITE;
417             break;
418           case CURL_OPPOSITE:
419             break;
420         }
421         break;
422     }
423   }
424 }
425 
426 static
rec_will(struct connectdata * conn,int option)427 void rec_will(struct connectdata *conn, int option)
428 {
429   struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
430   switch(tn->him[option])
431   {
432     case CURL_NO:
433       if(tn->him_preferred[option] == CURL_YES)
434       {
435         tn->him[option] = CURL_YES;
436         send_negotiation(conn, CURL_DO, option);
437       }
438       else
439       {
440         send_negotiation(conn, CURL_DONT, option);
441       }
442       break;
443 
444     case CURL_YES:
445       /* Already enabled */
446       break;
447 
448     case CURL_WANTNO:
449       switch(tn->himq[option])
450       {
451         case CURL_EMPTY:
452           /* Error: DONT answered by WILL */
453           tn->him[option] = CURL_NO;
454           break;
455         case CURL_OPPOSITE:
456           /* Error: DONT answered by WILL */
457           tn->him[option] = CURL_YES;
458           tn->himq[option] = CURL_EMPTY;
459           break;
460       }
461       break;
462 
463     case CURL_WANTYES:
464       switch(tn->himq[option])
465       {
466         case CURL_EMPTY:
467           tn->him[option] = CURL_YES;
468           break;
469         case CURL_OPPOSITE:
470           tn->him[option] = CURL_WANTNO;
471           tn->himq[option] = CURL_EMPTY;
472           send_negotiation(conn, CURL_DONT, option);
473           break;
474       }
475       break;
476   }
477 }
478 
479 static
rec_wont(struct connectdata * conn,int option)480 void rec_wont(struct connectdata *conn, int option)
481 {
482   struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
483   switch(tn->him[option])
484   {
485     case CURL_NO:
486       /* Already disabled */
487       break;
488 
489     case CURL_YES:
490       tn->him[option] = CURL_NO;
491       send_negotiation(conn, CURL_DONT, option);
492       break;
493 
494     case CURL_WANTNO:
495       switch(tn->himq[option])
496       {
497         case CURL_EMPTY:
498           tn->him[option] = CURL_NO;
499           break;
500 
501         case CURL_OPPOSITE:
502           tn->him[option] = CURL_WANTYES;
503           tn->himq[option] = CURL_EMPTY;
504           send_negotiation(conn, CURL_DO, option);
505           break;
506       }
507       break;
508 
509     case CURL_WANTYES:
510       switch(tn->himq[option])
511       {
512         case CURL_EMPTY:
513           tn->him[option] = CURL_NO;
514           break;
515         case CURL_OPPOSITE:
516           tn->him[option] = CURL_NO;
517           tn->himq[option] = CURL_EMPTY;
518           break;
519       }
520       break;
521   }
522 }
523 
524 static void
set_local_option(struct connectdata * conn,int option,int newstate)525 set_local_option(struct connectdata *conn, int option, int newstate)
526 {
527   struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
528   if(newstate == CURL_YES)
529   {
530     switch(tn->us[option])
531     {
532       case CURL_NO:
533         tn->us[option] = CURL_WANTYES;
534         send_negotiation(conn, CURL_WILL, option);
535         break;
536 
537       case CURL_YES:
538         /* Already enabled */
539         break;
540 
541       case CURL_WANTNO:
542         switch(tn->usq[option])
543         {
544           case CURL_EMPTY:
545             /* Already negotiating for CURL_YES, queue the request */
546             tn->usq[option] = CURL_OPPOSITE;
547             break;
548           case CURL_OPPOSITE:
549             /* Error: already queued an enable request */
550             break;
551         }
552         break;
553 
554       case CURL_WANTYES:
555         switch(tn->usq[option])
556         {
557           case CURL_EMPTY:
558             /* Error: already negotiating for enable */
559             break;
560           case CURL_OPPOSITE:
561             tn->usq[option] = CURL_EMPTY;
562             break;
563         }
564         break;
565     }
566   }
567   else /* NO */
568   {
569     switch(tn->us[option])
570     {
571       case CURL_NO:
572         /* Already disabled */
573         break;
574 
575       case CURL_YES:
576         tn->us[option] = CURL_WANTNO;
577         send_negotiation(conn, CURL_WONT, option);
578         break;
579 
580       case CURL_WANTNO:
581         switch(tn->usq[option])
582         {
583           case CURL_EMPTY:
584             /* Already negotiating for NO */
585             break;
586           case CURL_OPPOSITE:
587             tn->usq[option] = CURL_EMPTY;
588             break;
589         }
590         break;
591 
592       case CURL_WANTYES:
593         switch(tn->usq[option])
594         {
595           case CURL_EMPTY:
596             tn->usq[option] = CURL_OPPOSITE;
597             break;
598           case CURL_OPPOSITE:
599             break;
600         }
601         break;
602     }
603   }
604 }
605 
606 static
rec_do(struct connectdata * conn,int option)607 void rec_do(struct connectdata *conn, int option)
608 {
609   struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
610   switch(tn->us[option])
611   {
612     case CURL_NO:
613       if(tn->us_preferred[option] == CURL_YES)
614       {
615         tn->us[option] = CURL_YES;
616         send_negotiation(conn, CURL_WILL, option);
617       }
618       else
619       {
620         send_negotiation(conn, CURL_WONT, option);
621       }
622       break;
623 
624     case CURL_YES:
625       /* Already enabled */
626       break;
627 
628     case CURL_WANTNO:
629       switch(tn->usq[option])
630       {
631         case CURL_EMPTY:
632           /* Error: DONT answered by WILL */
633           tn->us[option] = CURL_NO;
634           break;
635         case CURL_OPPOSITE:
636           /* Error: DONT answered by WILL */
637           tn->us[option] = CURL_YES;
638           tn->usq[option] = CURL_EMPTY;
639           break;
640       }
641       break;
642 
643     case CURL_WANTYES:
644       switch(tn->usq[option])
645       {
646         case CURL_EMPTY:
647           tn->us[option] = CURL_YES;
648           break;
649         case CURL_OPPOSITE:
650           tn->us[option] = CURL_WANTNO;
651           tn->himq[option] = CURL_EMPTY;
652           send_negotiation(conn, CURL_WONT, option);
653           break;
654       }
655       break;
656   }
657 }
658 
659 static
rec_dont(struct connectdata * conn,int option)660 void rec_dont(struct connectdata *conn, int option)
661 {
662   struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
663   switch(tn->us[option])
664   {
665     case CURL_NO:
666       /* Already disabled */
667       break;
668 
669     case CURL_YES:
670       tn->us[option] = CURL_NO;
671       send_negotiation(conn, CURL_WONT, option);
672       break;
673 
674     case CURL_WANTNO:
675       switch(tn->usq[option])
676       {
677         case CURL_EMPTY:
678           tn->us[option] = CURL_NO;
679           break;
680 
681         case CURL_OPPOSITE:
682           tn->us[option] = CURL_WANTYES;
683           tn->usq[option] = CURL_EMPTY;
684           send_negotiation(conn, CURL_WILL, option);
685           break;
686       }
687       break;
688 
689     case CURL_WANTYES:
690       switch(tn->usq[option])
691       {
692         case CURL_EMPTY:
693           tn->us[option] = CURL_NO;
694           break;
695         case CURL_OPPOSITE:
696           tn->us[option] = CURL_NO;
697           tn->usq[option] = CURL_EMPTY;
698           break;
699       }
700       break;
701   }
702 }
703 
704 
printsub(struct SessionHandle * data,int direction,unsigned char * pointer,size_t length)705 static void printsub(struct SessionHandle *data,
706                      int direction,             /* '<' or '>' */
707                      unsigned char *pointer,    /* where suboption data is */
708                      size_t length)             /* length of suboption data */
709 {
710   unsigned int i = 0;
711 
712   if(data->set.verbose)
713   {
714     if(direction)
715     {
716       infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
717       if(length >= 3)
718       {
719         int j;
720 
721         i = pointer[length-2];
722         j = pointer[length-1];
723 
724         if(i != CURL_IAC || j != CURL_SE)
725         {
726           infof(data, "(terminated by ");
727           if(CURL_TELOPT_OK(i))
728             infof(data, "%s ", CURL_TELOPT(i));
729           else if(CURL_TELCMD_OK(i))
730             infof(data, "%s ", CURL_TELCMD(i));
731           else
732             infof(data, "%d ", i);
733           if(CURL_TELOPT_OK(j))
734             infof(data, "%s", CURL_TELOPT(j));
735           else if(CURL_TELCMD_OK(j))
736             infof(data, "%s", CURL_TELCMD(j));
737           else
738             infof(data, "%d", j);
739           infof(data, ", not IAC SE!) ");
740         }
741       }
742       length -= 2;
743     }
744     if(length < 1)
745     {
746       infof(data, "(Empty suboption?)");
747       return;
748     }
749 
750     if(CURL_TELOPT_OK(pointer[0])) {
751       switch(pointer[0]) {
752         case CURL_TELOPT_TTYPE:
753         case CURL_TELOPT_XDISPLOC:
754         case CURL_TELOPT_NEW_ENVIRON:
755           infof(data, "%s", CURL_TELOPT(pointer[0]));
756           break;
757         default:
758           infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
759           break;
760       }
761     }
762     else
763       infof(data, "%d (unknown)", pointer[i]);
764 
765     switch(pointer[1]) {
766       case CURL_TELQUAL_IS:
767         infof(data, " IS");
768         break;
769       case CURL_TELQUAL_SEND:
770         infof(data, " SEND");
771         break;
772       case CURL_TELQUAL_INFO:
773         infof(data, " INFO/REPLY");
774         break;
775       case CURL_TELQUAL_NAME:
776         infof(data, " NAME");
777         break;
778     }
779 
780     switch(pointer[0]) {
781       case CURL_TELOPT_TTYPE:
782       case CURL_TELOPT_XDISPLOC:
783         pointer[length] = 0;
784         infof(data, " \"%s\"", &pointer[2]);
785         break;
786       case CURL_TELOPT_NEW_ENVIRON:
787         if(pointer[1] == CURL_TELQUAL_IS) {
788           infof(data, " ");
789           for(i = 3;i < length;i++) {
790             switch(pointer[i]) {
791               case CURL_NEW_ENV_VAR:
792                 infof(data, ", ");
793                 break;
794               case CURL_NEW_ENV_VALUE:
795                 infof(data, " = ");
796                 break;
797               default:
798                 infof(data, "%c", pointer[i]);
799                 break;
800             }
801           }
802         }
803         break;
804       default:
805         for (i = 2; i < length; i++)
806           infof(data, " %.2x", pointer[i]);
807         break;
808     }
809 
810     if(direction)
811     {
812       infof(data, "\n");
813     }
814   }
815 }
816 
check_telnet_options(struct connectdata * conn)817 static CURLcode check_telnet_options(struct connectdata *conn)
818 {
819   struct curl_slist *head;
820   char option_keyword[128];
821   char option_arg[256];
822   char *buf;
823   struct SessionHandle *data = conn->data;
824   struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
825 
826   /* Add the user name as an environment variable if it
827      was given on the command line */
828   if(conn->bits.user_passwd)
829   {
830     snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
831     tn->telnet_vars = curl_slist_append(tn->telnet_vars, option_arg);
832 
833     tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
834   }
835 
836   for(head = data->set.telnet_options; head; head=head->next) {
837     if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
838               option_keyword, option_arg) == 2) {
839 
840       /* Terminal type */
841       if(Curl_raw_equal(option_keyword, "TTYPE")) {
842         strncpy(tn->subopt_ttype, option_arg, 31);
843         tn->subopt_ttype[31] = 0; /* String termination */
844         tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
845         continue;
846       }
847 
848       /* Display variable */
849       if(Curl_raw_equal(option_keyword, "XDISPLOC")) {
850         strncpy(tn->subopt_xdisploc, option_arg, 127);
851         tn->subopt_xdisploc[127] = 0; /* String termination */
852         tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
853         continue;
854       }
855 
856       /* Environment variable */
857       if(Curl_raw_equal(option_keyword, "NEW_ENV")) {
858         buf = strdup(option_arg);
859         if(!buf)
860           return CURLE_OUT_OF_MEMORY;
861         tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf);
862         tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
863         continue;
864       }
865 
866       failf(data, "Unknown telnet option %s", head->data);
867       return CURLE_UNKNOWN_TELNET_OPTION;
868     } else {
869       failf(data, "Syntax error in telnet option: %s", head->data);
870       return CURLE_TELNET_OPTION_SYNTAX;
871     }
872   }
873 
874   return CURLE_OK;
875 }
876 
877 /*
878  * suboption()
879  *
880  * Look at the sub-option buffer, and try to be helpful to the other
881  * side.
882  */
883 
suboption(struct connectdata * conn)884 static void suboption(struct connectdata *conn)
885 {
886   struct curl_slist *v;
887   unsigned char temp[2048];
888   ssize_t bytes_written;
889   size_t len;
890   size_t tmplen;
891   int err;
892   char varname[128];
893   char varval[128];
894   struct SessionHandle *data = conn->data;
895   struct TELNET *tn = (struct TELNET *)data->state.proto.telnet;
896 
897   printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
898   switch (CURL_SB_GET(tn)) {
899     case CURL_TELOPT_TTYPE:
900       len = strlen(tn->subopt_ttype) + 4 + 2;
901       snprintf((char *)temp, sizeof(temp),
902                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
903                CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
904       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
905       if(bytes_written < 0) {
906         err = SOCKERRNO;
907         failf(data,"Sending data failed (%d)",err);
908       }
909       printsub(data, '>', &temp[2], len-2);
910       break;
911     case CURL_TELOPT_XDISPLOC:
912       len = strlen(tn->subopt_xdisploc) + 4 + 2;
913       snprintf((char *)temp, sizeof(temp),
914                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
915                CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
916       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
917       if(bytes_written < 0) {
918         err = SOCKERRNO;
919         failf(data,"Sending data failed (%d)",err);
920       }
921       printsub(data, '>', &temp[2], len-2);
922       break;
923     case CURL_TELOPT_NEW_ENVIRON:
924       snprintf((char *)temp, sizeof(temp),
925                "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
926                CURL_TELQUAL_IS);
927       len = 4;
928 
929       for(v = tn->telnet_vars;v;v = v->next) {
930         tmplen = (strlen(v->data) + 1);
931         /* Add the variable only if it fits */
932         if(len + tmplen < (int)sizeof(temp)-6) {
933           sscanf(v->data, "%127[^,],%127s", varname, varval);
934           snprintf((char *)&temp[len], sizeof(temp) - len,
935                    "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
936                    CURL_NEW_ENV_VALUE, varval);
937           len += tmplen;
938         }
939       }
940       snprintf((char *)&temp[len], sizeof(temp) - len,
941                "%c%c", CURL_IAC, CURL_SE);
942       len += 2;
943       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
944       if(bytes_written < 0) {
945         err = SOCKERRNO;
946         failf(data,"Sending data failed (%d)",err);
947       }
948       printsub(data, '>', &temp[2], len-2);
949       break;
950   }
951   return;
952 }
953 
954 static
telrcv(struct connectdata * conn,const unsigned char * inbuf,ssize_t count)955 void telrcv(struct connectdata *conn,
956             const unsigned char *inbuf, /* Data received from socket */
957             ssize_t count)              /* Number of bytes received */
958 {
959   unsigned char c;
960   int in = 0;
961   int startwrite=-1;
962   struct SessionHandle *data = conn->data;
963   struct TELNET *tn = (struct TELNET *)data->state.proto.telnet;
964 
965 #define startskipping() \
966     if(startwrite >= 0) \
967        Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&inbuf[startwrite], in-startwrite); \
968     startwrite = -1
969 
970 #define writebyte() \
971     if(startwrite < 0) \
972       startwrite = in
973 
974 #define bufferflush() startskipping()
975 
976   while(count--)
977   {
978     c = inbuf[in];
979 
980     /*infof(data,"In rcv state %d char %d\n", tn->telrcv_state, c);*/
981     switch (tn->telrcv_state)
982     {
983       case CURL_TS_CR:
984         tn->telrcv_state = CURL_TS_DATA;
985         if(c == '\0')
986         {
987           startskipping();
988           break;   /* Ignore \0 after CR */
989         }
990         writebyte();
991         break;
992 
993       case CURL_TS_DATA:
994         if(c == CURL_IAC)
995         {
996           tn->telrcv_state = CURL_TS_IAC;
997           startskipping();
998           break;
999         }
1000         else if(c == '\r')
1001         {
1002           tn->telrcv_state = CURL_TS_CR;
1003         }
1004         writebyte();
1005         break;
1006 
1007       case CURL_TS_IAC:
1008       process_iac:
1009       DEBUGASSERT(startwrite < 0);
1010       switch (c)
1011       {
1012         case CURL_WILL:
1013           tn->telrcv_state = CURL_TS_WILL;
1014           break;
1015         case CURL_WONT:
1016           tn->telrcv_state = CURL_TS_WONT;
1017           break;
1018         case CURL_DO:
1019           tn->telrcv_state = CURL_TS_DO;
1020           break;
1021         case CURL_DONT:
1022           tn->telrcv_state = CURL_TS_DONT;
1023           break;
1024         case CURL_SB:
1025           CURL_SB_CLEAR(tn);
1026           tn->telrcv_state = CURL_TS_SB;
1027           break;
1028         case CURL_IAC:
1029           tn->telrcv_state = CURL_TS_DATA;
1030           writebyte();
1031           break;
1032         case CURL_DM:
1033         case CURL_NOP:
1034         case CURL_GA:
1035         default:
1036           tn->telrcv_state = CURL_TS_DATA;
1037           printoption(data, "RCVD", CURL_IAC, c);
1038           break;
1039       }
1040       break;
1041 
1042       case CURL_TS_WILL:
1043         printoption(data, "RCVD", CURL_WILL, c);
1044         tn->please_negotiate = 1;
1045         rec_will(conn, c);
1046         tn->telrcv_state = CURL_TS_DATA;
1047         break;
1048 
1049       case CURL_TS_WONT:
1050         printoption(data, "RCVD", CURL_WONT, c);
1051         tn->please_negotiate = 1;
1052         rec_wont(conn, c);
1053         tn->telrcv_state = CURL_TS_DATA;
1054         break;
1055 
1056       case CURL_TS_DO:
1057         printoption(data, "RCVD", CURL_DO, c);
1058         tn->please_negotiate = 1;
1059         rec_do(conn, c);
1060         tn->telrcv_state = CURL_TS_DATA;
1061         break;
1062 
1063       case CURL_TS_DONT:
1064         printoption(data, "RCVD", CURL_DONT, c);
1065         tn->please_negotiate = 1;
1066         rec_dont(conn, c);
1067         tn->telrcv_state = CURL_TS_DATA;
1068         break;
1069 
1070       case CURL_TS_SB:
1071         if(c == CURL_IAC)
1072         {
1073           tn->telrcv_state = CURL_TS_SE;
1074         }
1075         else
1076         {
1077           CURL_SB_ACCUM(tn,c);
1078         }
1079         break;
1080 
1081       case CURL_TS_SE:
1082         if(c != CURL_SE)
1083         {
1084           if(c != CURL_IAC)
1085           {
1086             /*
1087              * This is an error.  We only expect to get "IAC IAC" or "IAC SE".
1088              * Several things may have happend.  An IAC was not doubled, the
1089              * IAC SE was left off, or another option got inserted into the
1090              * suboption are all possibilities.  If we assume that the IAC was
1091              * not doubled, and really the IAC SE was left off, we could get
1092              * into an infinate loop here.  So, instead, we terminate the
1093              * suboption, and process the partial suboption if we can.
1094              */
1095             CURL_SB_ACCUM(tn, CURL_IAC);
1096             CURL_SB_ACCUM(tn, c);
1097             tn->subpointer -= 2;
1098             CURL_SB_TERM(tn);
1099 
1100             printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
1101             suboption(conn);   /* handle sub-option */
1102             tn->telrcv_state = CURL_TS_IAC;
1103             goto process_iac;
1104           }
1105           CURL_SB_ACCUM(tn,c);
1106           tn->telrcv_state = CURL_TS_SB;
1107         }
1108         else
1109         {
1110           CURL_SB_ACCUM(tn, CURL_IAC);
1111           CURL_SB_ACCUM(tn, CURL_SE);
1112           tn->subpointer -= 2;
1113           CURL_SB_TERM(tn);
1114           suboption(conn);   /* handle sub-option */
1115           tn->telrcv_state = CURL_TS_DATA;
1116         }
1117         break;
1118     }
1119     ++in;
1120   }
1121   bufferflush();
1122 }
1123 
1124 /* Escape and send a telnet data block */
1125 /* TODO: write large chunks of data instead of one byte at a time */
send_telnet_data(struct connectdata * conn,char * buffer,ssize_t nread)1126 static CURLcode send_telnet_data(struct connectdata *conn,
1127                                  char *buffer, ssize_t nread)
1128 {
1129   unsigned char outbuf[2];
1130   ssize_t bytes_written, total_written;
1131   int out_count;
1132   CURLcode rc = CURLE_OK;
1133 
1134   while(rc == CURLE_OK && nread--) {
1135     outbuf[0] = *buffer++;
1136     out_count = 1;
1137     if(outbuf[0] == CURL_IAC)
1138       outbuf[out_count++] = CURL_IAC;
1139 
1140     total_written = 0;
1141     do {
1142       /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1143       struct pollfd pfd[1];
1144       pfd[0].fd = conn->sock[FIRSTSOCKET];
1145       pfd[0].events = POLLOUT;
1146       switch (Curl_poll(pfd, 1, -1)) {
1147         case -1:                    /* error, abort writing */
1148         case 0:                     /* timeout (will never happen) */
1149           rc = CURLE_SEND_ERROR;
1150           break;
1151         default:                    /* write! */
1152           bytes_written = 0;
1153           rc = Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf+total_written,
1154                           out_count-total_written, &bytes_written);
1155           total_written += bytes_written;
1156           break;
1157       }
1158     /* handle partial write */
1159     } while (rc == CURLE_OK && total_written < out_count);
1160   }
1161   return rc;
1162 }
1163 
telnet_done(struct connectdata * conn,CURLcode status,bool premature)1164 static CURLcode telnet_done(struct connectdata *conn,
1165                                  CURLcode status, bool premature)
1166 {
1167   struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
1168   (void)status; /* unused */
1169   (void)premature; /* not used */
1170 
1171   curl_slist_free_all(tn->telnet_vars);
1172 
1173   free(conn->data->state.proto.telnet);
1174   conn->data->state.proto.telnet = NULL;
1175 
1176   return CURLE_OK;
1177 }
1178 
telnet_do(struct connectdata * conn,bool * done)1179 static CURLcode telnet_do(struct connectdata *conn, bool *done)
1180 {
1181   CURLcode code;
1182   struct SessionHandle *data = conn->data;
1183   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1184 #ifdef USE_WINSOCK
1185   HMODULE wsock2;
1186   WSOCK2_FUNC close_event_func;
1187   WSOCK2_FUNC create_event_func;
1188   WSOCK2_FUNC event_select_func;
1189   WSOCK2_FUNC enum_netevents_func;
1190   WSAEVENT event_handle;
1191   WSANETWORKEVENTS events;
1192   HANDLE stdin_handle;
1193   HANDLE objs[2];
1194   DWORD  obj_count;
1195   DWORD  wait_timeout;
1196   DWORD waitret;
1197   DWORD readfile_read;
1198 #else
1199   int interval_ms;
1200   struct pollfd pfd[2];
1201 #endif
1202   ssize_t nread;
1203   bool keepon = TRUE;
1204   char *buf = data->state.buffer;
1205   struct TELNET *tn;
1206 
1207   *done = TRUE; /* unconditionally */
1208 
1209   code = init_telnet(conn);
1210   if(code)
1211     return code;
1212 
1213   tn = (struct TELNET *)data->state.proto.telnet;
1214 
1215   code = check_telnet_options(conn);
1216   if(code)
1217     return code;
1218 
1219 #ifdef USE_WINSOCK
1220   /*
1221   ** This functionality only works with WinSock >= 2.0.  So,
1222   ** make sure have it.
1223   */
1224   code = check_wsock2(data);
1225   if(code)
1226     return code;
1227 
1228   /* OK, so we have WinSock 2.0.  We need to dynamically */
1229   /* load ws2_32.dll and get the function pointers we need. */
1230   wsock2 = LoadLibrary("WS2_32.DLL");
1231   if(wsock2 == NULL) {
1232     failf(data,"failed to load WS2_32.DLL (%d)", ERRNO);
1233     return CURLE_FAILED_INIT;
1234   }
1235 
1236   /* Grab a pointer to WSACreateEvent */
1237   create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
1238   if(create_event_func == NULL) {
1239     failf(data,"failed to find WSACreateEvent function (%d)",
1240           ERRNO);
1241     FreeLibrary(wsock2);
1242     return CURLE_FAILED_INIT;
1243   }
1244 
1245   /* And WSACloseEvent */
1246   close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
1247   if(close_event_func == NULL) {
1248     failf(data,"failed to find WSACloseEvent function (%d)",
1249           ERRNO);
1250     FreeLibrary(wsock2);
1251     return CURLE_FAILED_INIT;
1252   }
1253 
1254   /* And WSAEventSelect */
1255   event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
1256   if(event_select_func == NULL) {
1257     failf(data,"failed to find WSAEventSelect function (%d)",
1258           ERRNO);
1259     FreeLibrary(wsock2);
1260     return CURLE_FAILED_INIT;
1261   }
1262 
1263   /* And WSAEnumNetworkEvents */
1264   enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
1265   if(enum_netevents_func == NULL) {
1266     failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
1267           ERRNO);
1268     FreeLibrary(wsock2);
1269     return CURLE_FAILED_INIT;
1270   }
1271 
1272   /* We want to wait for both stdin and the socket. Since
1273   ** the select() function in winsock only works on sockets
1274   ** we have to use the WaitForMultipleObjects() call.
1275   */
1276 
1277   /* First, create a sockets event object */
1278   event_handle = (WSAEVENT)create_event_func();
1279   if(event_handle == WSA_INVALID_EVENT) {
1280     failf(data,"WSACreateEvent failed (%d)", SOCKERRNO);
1281     FreeLibrary(wsock2);
1282     return CURLE_FAILED_INIT;
1283   }
1284 
1285   /* The get the Windows file handle for stdin */
1286   stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1287 
1288   /* Create the list of objects to wait for */
1289   objs[0] = event_handle;
1290   objs[1] = stdin_handle;
1291 
1292   /* Tell winsock what events we want to listen to */
1293   if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
1294     close_event_func(event_handle);
1295     FreeLibrary(wsock2);
1296     return CURLE_OK;
1297   }
1298 
1299   /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1300      else use the old WaitForMultipleObjects() way */
1301   if(GetFileType(stdin_handle) == FILE_TYPE_PIPE) {
1302     /* Don't wait for stdin_handle, just wait for event_handle */
1303     obj_count = 1;
1304     /* Check stdin_handle per 100 milliseconds */
1305     wait_timeout = 100;
1306   } else {
1307     obj_count = 2;
1308     wait_timeout = INFINITE;
1309   }
1310 
1311   /* Keep on listening and act on events */
1312   while(keepon) {
1313     waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
1314     switch(waitret) {
1315     case WAIT_TIMEOUT:
1316     {
1317       while(1) {
1318         if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) {
1319           keepon = FALSE;
1320           code = CURLE_READ_ERROR;
1321           break;
1322         }
1323 
1324         if(!readfile_read)
1325           break;
1326 
1327         if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1328                      &readfile_read, NULL)) {
1329           keepon = FALSE;
1330           code = CURLE_READ_ERROR;
1331           break;
1332         }
1333 
1334         code = send_telnet_data(conn, buf, readfile_read);
1335         if(code) {
1336           keepon = FALSE;
1337           break;
1338         }
1339       }
1340     }
1341     break;
1342 
1343     case WAIT_OBJECT_0 + 1:
1344     {
1345       if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1346                    &readfile_read, NULL)) {
1347         keepon = FALSE;
1348         code = CURLE_READ_ERROR;
1349         break;
1350       }
1351 
1352       code = send_telnet_data(conn, buf, readfile_read);
1353       if(code) {
1354         keepon = FALSE;
1355         break;
1356       }
1357     }
1358     break;
1359 
1360     case WAIT_OBJECT_0:
1361       if(enum_netevents_func(sockfd, event_handle, &events)
1362          != SOCKET_ERROR) {
1363         if(events.lNetworkEvents & FD_READ) {
1364           /* This reallu OUGHT to check its return code. */
1365           (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1366 
1367           telrcv(conn, (unsigned char *)buf, nread);
1368 
1369           fflush(stdout);
1370 
1371           /* Negotiate if the peer has started negotiating,
1372              otherwise don't. We don't want to speak telnet with
1373              non-telnet servers, like POP or SMTP. */
1374           if(tn->please_negotiate && !tn->already_negotiated) {
1375             negotiate(conn);
1376             tn->already_negotiated = 1;
1377           }
1378         }
1379 
1380         if(events.lNetworkEvents & FD_CLOSE) {
1381           keepon = FALSE;
1382         }
1383       }
1384       break;
1385     }
1386   }
1387 
1388   /* We called WSACreateEvent, so call WSACloseEvent */
1389   if(close_event_func(event_handle) == FALSE) {
1390     infof(data,"WSACloseEvent failed (%d)", SOCKERRNO);
1391   }
1392 
1393   /* "Forget" pointers into the library we're about to free */
1394   create_event_func = NULL;
1395   close_event_func = NULL;
1396   event_select_func = NULL;
1397   enum_netevents_func = NULL;
1398 
1399   /* We called LoadLibrary, so call FreeLibrary */
1400   if(!FreeLibrary(wsock2))
1401     infof(data,"FreeLibrary(wsock2) failed (%d)", ERRNO);
1402 #else
1403   pfd[0].fd = sockfd;
1404   pfd[0].events = POLLIN;
1405   pfd[1].fd = 0;
1406   pfd[1].events = POLLIN;
1407   interval_ms = 1 * 1000;
1408 
1409   while(keepon) {
1410     switch (Curl_poll(pfd, 2, interval_ms)) {
1411     case -1:                    /* error, stop reading */
1412       keepon = FALSE;
1413       continue;
1414     case 0:                     /* timeout */
1415       break;
1416     default:                    /* read! */
1417       if(pfd[1].revents & POLLIN) { /* read from stdin */
1418         nread = read(0, buf, 255);
1419         code = send_telnet_data(conn, buf, nread);
1420         if(code) {
1421           keepon = FALSE;
1422           break;
1423         }
1424       }
1425 
1426       if(pfd[0].revents & POLLIN) {
1427         /* This OUGHT to check the return code... */
1428         (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1429 
1430         /* if we receive 0 or less here, the server closed the connection and
1431            we bail out from this! */
1432         if(nread <= 0) {
1433           keepon = FALSE;
1434           break;
1435         }
1436 
1437         telrcv(conn, (unsigned char *)buf, nread);
1438 
1439         /* Negotiate if the peer has started negotiating,
1440            otherwise don't. We don't want to speak telnet with
1441            non-telnet servers, like POP or SMTP. */
1442         if(tn->please_negotiate && !tn->already_negotiated) {
1443           negotiate(conn);
1444           tn->already_negotiated = 1;
1445         }
1446       }
1447     }
1448     if(data->set.timeout) {
1449       struct timeval now;           /* current time */
1450       now = Curl_tvnow();
1451       if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1452         failf(data, "Time-out");
1453         code = CURLE_OPERATION_TIMEDOUT;
1454         keepon = FALSE;
1455       }
1456     }
1457   }
1458 #endif
1459   /* mark this as "no further transfer wanted" */
1460   Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1461 
1462   return code;
1463 }
1464 #endif
1465